I'm having some problems witht the scoping of item groups I create in an MSBuild script. Basically, what I want to do is to have two different targets - let's call them RunUnitTests
and RunIntegrationTests
- that generate an item group called TestAssemblies
and then call RunTests
, which uses TestAssemblies
to determine which assemblies to run tests from.
The two different targets for unit and integration tests both depend on the build target and get an item group with all compiled assemblies from there, but since the RunTests
target will be called from different places, it can't really depend on either of them. Thus, I need to pass the item group to the common testrunner target somehow. However, this seems to be impossible, because changes to an item group within a target seems to be scoped to only work within that target.
I've seen these posts, but they only seem to confirm my fears, and suggest DependsOnTarget
as a workaround - which won't work for me, since I need to get the items from different places on different runs.
This is what I have so far:
<Target Name="RunAllTests" DependsOnTarget="BuildProject">
<!-- In here, items created in BuildProject are available. -->
<CallTarget Targets="RunUnitTests;RunIntegrationTests">
</Target>
<Target Name="RunUnitTests" DependsOnTarget="BuildProject">
<!-- In here, items created in BuildProject are available. -->
<!-- One of those is @(UnitTestAssemblies) -->
<CreateItem Include="@(UnitTestAssemblies)">
<Output TaskParameter="Include" ItemName="TestAssemblies" />
</CreateItem>
<CallTarget Targets="RunTests" />
</Target>
<!-- Then there's a similar target named RunIntegrationTests, which does the
same as RunUnitTests except it includes @(IntegrationTestAssemblies) -->
<Target Name="RunTests">
<!-- Here, I'd like to access @(TestAssemblies) and pass them to the NUnit
task, but they have fallen out of scope. -->
</Target>
Is there any way around this, or will I have to completely restructure my build script?
Changes to an item group within a target are only visible to other targets after the changing target exits. So to get the list of test assemblies to stick, you may have to move actually setting up the targets to its own target as in the following:
<Target Name="PrepareUnitTestList" DependsOnTarget="BuildProject">
<ItemGroup>
<TestAssemblies Include="@(UnitTestAssemblies)"/>
</ItemGroup>
</Target>
<Target Name="RunUnitTests" DependsOnTargets="PrepareUnitTestList">
<CallTarget Targets="RunTests"/>
</Target>
<Target Name="RunTests">
<Message Text="Test: %(TestAssemblies.Identity)"/>
</Target>
In "MSBuild" task you can pass properties to targets, but I'm not sure if it will work for ItemGroup. But you definitely can do it through batching - passing one assembly at a time.
<Target Name="RunUnitTests">
<MSBuild Projects="$(MSBuildProjectFullPath)" Targets="RunTests" Properties="TestAssemblies=%(TestAssemblies.Identity)"/>
</Target>
It would run the "RunTests" for only one assembly at a time, so it will be useless if you need knowledge of other assemblies at time of running tests. But maybe it will give some better ideas how to resolve this problem...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With