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.