Search code examples
msbuildncover

MSBUILD Run NCover Against Matched Projects


I am using MSBuild and am getting all test projects using a regex on the project name, like this.

<RegexMatch Input="@(AllProjects)" Expression="(.)*Test(.)*">
    <Output  TaskParameter="Output" ItemName="UnitTestProjects"/>
</RegexMatch>

I now want to use @(UnitTestProjects) and pass them all to NCover to check that the tests are all giving 100% coverage.

To do this on a single project, I do something like this:

<Target Name="Coverage">
    <NCover TestRunnerExe="C:\Program Files\NUnit 2.5.8\bin\net-2.0\nunit-console.exe"
        TestRunnerArgs="&quot;C:\SomeProject\bin\SomeProject.dll&quot; &quot;C:\SomeProject\bin\SomeProjectTest.dll&quot;"
        WorkingDirectory="C:\SomeProject\bin\"
        AppendTrendTo="coverage.trend"
        OnlyAssembliesWithSource="True"
        ProjectName="SomeProjectCoverage"    />
</Target>

How do I effectively use @(UnitTestProjects) in the context of this NCover target?


Solution

  • For batching your @(UnitTestProjects) your Target will have to use it like this:

    <Target Name="Coverage">
        <NCover TestRunnerExe="C:\Program Files\NUnit 2.5.8\bin\net-2.0\nunit-console.exe"
        TestRunnerArgs="&quot;%(UnitTestProjects.Identity)&quot; &quot;%(UnitTestProjects.Identity)&quot;"
    
    <!--
    If you receive the Task Output (*Test.dll) you will have to extract
    the working dir path
    -->
        WorkingDirectory="C:\SomeProject\bin\"
        AppendTrendTo="coverage.trend"
        OnlyAssembliesWithSource="True"
    <!--
    ... the same thing applies to finding out the current project name
    from your Task Ouput.
    -->
        ProjectName="SomeProjectCoverage"    />
    </Target>
    

    A more reliable solution would be, to provide a list of TaskItems, holding metadata about your (Test)project.

    <ItemGroup>
        <TestProject Include="MyProject1.Test.dll">
            <TestProjectName>MyProject1</TestProjectName>
            <MyTestProjectWorkingDir>C:\MyProject1\bin</MyTestProjectWorkingDir>
        </TestProject>
        <TestProject Include="MyProject2.Test.dll">
            <TestProjectName>MyProject2</TestProjectName>
            <MyTestProjectWorkingDir>C:\MyProject2\bin</MyTestProjectWorkingDir>
        </TestProject>
    </ItemGroup>
    
    <Target Name="Coverage">
        <NCover TestRunnerExe="C:\Program Files\NUnit 2.5.8\bin\net-2.0\nunit-console.exe"
        TestRunnerArgs="&quot;%(TestProject.Identity)&quot; &quot;%(TestProject.Identity)&quot;"
        WorkingDirectory="%(TestProject.MyTestProjectWorkingDir)"
        AppendTrendTo="coverage.trend"
        OnlyAssembliesWithSource="True"
        ProjectName="%(TestProject.MyTestProjectName)"    />
    </Target>
    

    Your question suggests that you are looking for an automated approach which will allow you to add new test projects without having to maintain a configuration list of TaskItems.

    Since it would be quite difficult, to extract all the information needed to feed your NCover Task maybe a semi-automated approach might work for you.

    You could add an import to your test project which will feed your global test project ItemGroup:

    <ItemGroup>
        <!-- add existing ItemGroup -->
        <TestProject Include="@(TestProject)" />
    
        <!-- add project itself -->
        <TestProject Include="MyProject1.Test.dll">
            <TestProjectName>MyProject1</TestProjectName>
            <MyTestProjectWorkingDir>C:\MyProject1\bin</MyTestProjectWorkingDir>
        </TestProject>
    </ItemGroup>
    

    The usage in your NCover Task will be the same as above.

    This way your master build script doesn't need to know about any specific test project; it just processes your ItemGroup "TestProject".