How to: Visual Studio test runner & side by side test code
After spending a lot of time with xUnit.net I recently had to go back to MSTest for my testing again (because it’s the de facto standard at my current client which is not negotiable ;-().
Former colleagues of mine will probably laugh about this, because I’ve had a love-and-hate-relationship with MSTest and especially the VisualStudio runner in the past. I won’t go into details here, but you can read about it here. However since I currently have no other option I use what is there. Better writing tests such an environment, than writing no test at all. At least if you ask me.
This brings me back to the topic of the post. Some prerequisites: I like developing software in a TDD manner and am using Resharper with its ‘Generate’ and ‘Move To’ features a lot. I like the idea of having test-code side by side with the actual tested code. With this a lot of you’re daily TDD life becomes at least a bit easier and painless. I see at least two advantages in such an approach:- You don’t have to copy generated classes from the test-assembly to the regular assembly.
- You don’t have to maintain two different folder hierarchies (The one in the code-assembly and the one in the regular assembly) and therefore know exactly where to look for test-code.
Step 1: Add the ProjectType Guids to your project.
VisualStudio’s test explorer scans only projects which are of a certain project type (aka the test project) for tests. VS identifies such a project based on the value of a particular node in the .csproj file, the ProjectTypeGuid node. Simply copy this one from an actual test project to the .csproj of your regular assembly. Another option of course would be to start with a test project from scratch.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<!-- The line below has to be added to regular projects -->
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<ProjectGuid>{890DA3CA-999A-474E-BA87-05A834CAB7B8}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpecReport</RootNamespace>
<AssemblyName>SpecReport</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
Step 2: Apply conditional compilation for not including the test code when compiling in release mode
So, the tests sit right next to the tested code, right? We presumable don’t want our tests to be deployed to production. We can achieve this in MSBuild fairly easy with conditional compilation and wildcards.
<ItemGroup>
<!-- The line below skips all files ending with 'Spec.cs' when compiling in a mode other than DEBUG -->
<Compile Condition="'$(Configuration)' == 'Debug'" Include="**\*Specs.cs" />
<Compile Include="IReportEngine.cs" />
<Compile Include="IReportGenerator.cs" />
<Compile Include="Notification.cs" />
<Compile Include="NotificationCollection.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReportEngine.cs" />
<Compile Include="ReportEngineArgs.cs" />
</ItemGroup>
Step 3: Apply conditional compilation for not deploying the test-related assemblies when compiling in release mode
<ItemGroup>
<Reference Condition="'$(Configuration)' == 'Debug'" Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Condition="'$(Configuration)' == 'Debug'" Include="Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Externals\RhinoMocks35\Rhino.Mocks.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
Et voila: The approach described in this post seams to work fine. At least I’m not experiencing side effects since I’ve configured it that way …


One Response Leave a comment
Cool idea! Looks like a nice pair of project and item templates. So that the newly added specs are automatically excluded from the release build.