Saturday, March 27, 2010

NUnit and CruiseControl

One of my goals is to become more skilled with CruiseControl.NET because Continuous Integration plays a big part in Agile Development. Today I took the first step. It wasn't one of those easy, comfortable steps. That's why I'm documenting my results.

Here are some of the steps I took today to get a CruiseControl server running on my computer with integrated NUnit Reports. Some of these steps could definitely be improved upon. I don't like using absolute paths if I don't have to but I broke that rule left and right. This is just the first time I've gotten all this working (and trust me, it took hours).

Install Cruise Control

I installed version 1.5.6804.1 of CruiseControl.NET and after realizing that by default Vista does not enable ASP.NET, it ran quite nicely.

Incorporte NUnit into the Build Process

I wanted to make NUnit run as part of the Visual Studio 2008 build process. I tried to use the Microsft SDC NUnit Task but after hours of tracking down unhandled exceptions in the NUnit task, I decided to switch to Tigris' MSBuild NUnit Task which worked great the first time.

I had to import the tasks in my Unit Test assembly's csproj file:

<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

And then I added the following to the same csproj file:

<IemGroup>
<TestAssemblies Include="$(TargetPath)"/>
</ItemGroup>

<Target Name="Test">
<NUnit
Assemblies="@(TestAssemblies)"
ToolPath="C:\Program Files (x86)\NUnit 2.5.3\bin\net-2.0" />
</Target>

The last step was to add "Test" to the Project element's DefaultTargets attribute:

<Project ToolsVersion="3.5" DefaultTargets="Build;Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Now, whenever I built the project, the tests would run. If the tests failed, the build would fail too. I had to change the MSBuild verbosity to normal to see the actual results of the unit tests. This has the side-effect of showing too much information. If I figure out how to get the NUnit test results showing without showing too much information, I'll write another blog entry.

Build the Project with CruiseControl

I added the following to my ccnet.config file:

<project name="MyProduct">
<category>Production Code</category>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\Users\Tim\Projects\CruiseControl\CruiseControlTests</workingDirectory>
<projectFile>CruiseControlTests.csproj</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /p:Platform=AnyCPU /v:diag</buildArgs>
<targets>Build;Test</targets>
<timeout>900</timeout>
<logger>C:\Program Files (x86)\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
<publishers>
<merge>
<files>
<file>C:\Users\Tim\Projects\CruiseControl\CruiseControlTests\TestResult.xml</file>
</files>
</merge>
<xmllogger/>
</publishers>
</project>

The merge elements are required so that the output of the unit test run could be reported on.

Getting Reporting To Work

In the dashboard.config file I had to make a few changes too. To make a change take effect, I'd recycle the CruiseControl app pool.

I added the following elements (shown in context):

<buildPlugins>
<buildReportBuildPlugin>
<xslFileNames>
<xslFile>xsl\unittests.xsl</xslFile>

and then I added this right after </buildReportBuildPlugin>:

<xslReportBuildPlugin description="NUnit Details" actionName="NUnitDetailsBuildReport" xslFileName="xsl\tests.xsl" />
<xslReportBuildPlugin description="NUnit Timings" actionName="NUnitTimingsBuildReport" xslFileName="xsl\timing.xsl" />

After recycling the app pool, everything worked great.

2 comments:

Slava Imeshev said...

If you want an "easy, comfortable step", you might want to check out our Parabuild for Continuous Integration. It takes 1 minute to set up and 5 minutes to the first build. It is integrated with NUnit and provides formatted reports and statistics for NUnit out of the box, no need to edit weirdly structured XML files.

Anonymous said...
This comment has been removed by a blog administrator.