OrthoCoders

You can code it, I can help!

How to Use MSbuild to Build and Test

What is a build script?

A build script is a small program written in the language of your choice that usually has more than one task used by the developer to build, test, deploy, etc...

Why do I need a build script?

A build script can give you the ability to compile, run tests, and build libraries, etc, without using the IDE. This is most useful before committing code to the repository and also, after the source is committed before being run by the continuous integration service.

Doing all these tasks manually can be tedious and error prone.  If you are also suffering from lack of documentation the knowledge of the process will leave with the developer in charge of compiling, building, etc.

Thus, instead of spending time writing documentation why not write a script to do all the steps for us and achieve the same results?

Enters MS Build

MS provides a script building language based on XML. Very similar to Ant and NMake this XML based script has many predefined tasks that allow us to compile, build, etc, etc...

How do I Start?

Here is a minimal ms build file called algorithm.msbuild used to compile our solution in release mode:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<ItemGroup>
		<Solutions Include="**\*.sln"/>
	</ItemGroup>

	<Target Name="Build">
		<MSBuild Projects="@(Solutions)" Properties="Configuration=Release"/>
	</Target>
</Project>
The project tasks are identified by the tag Target . The code above defines one called Build. Inside the task you can see a call to the MSBuild task used to compile all the solutions defined in the variable @Solutions. This variable is declared inside an ItemGroup which allow us to use the wildcards to match all the solutions in our current folder and subfolders. To run this file, open a command window and run:
msbuild algorithm.msbuild  /t:Build

Clean and rebuild

In order to rebuild our assemblies we need to be able to clean all the projects and then build them again. In order to do that we are going to use the internal predefined task Clean that comes with the default target definitions when you install vs.
<Target Name="Clean">
     <MSBuild Targets="Clean" Projects="@(Solutions)" Properties="Configuration=Release"/>
</Target>

<Target Name="Rebuild">
     <CallTarget Targets="Clean;Build"/>
</Target>
The Rebuild target uses the previous defined targets Build and Clean to achieve our goal.

Testing

Testing is an integral part of development and for each library or executable we build we should have our test counterpart.

In this case I'm using MBunit and when you install Gallio (test runner) it will also install an assembly with MSBuild related tasks to be used in our scripts.

First we have to include the Gallio task library to be used in our script file and then we can call the test runner to load all our assemblies that contain tests.

<UsingTask TaskName="Gallio.MSBuildTasks.Gallio" AssemblyFile="c:\program files\gallio\bin\Gallio.MSBuildTasks.dll"/>
<Target Name="Test">
     <ItemGroup>
          <TestAssemblies Include="**\bin\release\*.Tests.dll"/>
     </ItemGroup>
     <Gallio Assemblies="@(TestAssemblies)"   
          WorkingDirectory=""
          ApplicationBaseDirectory="$(SolutionFolder)\src\"
          IgnoreFailures="true"
          ReportDirectory="$(CCNetLastBuildFolder)"
          reportNameFormat="Test-Report"
          ReportTypes="Xml"
          ShowReports="false"
          >
          <Output TaskParameter="ExitCode" PropertyName="ExitCode" />
     </Gallio>
     <Error Text="Testing failed" Condition="$(ExitCode) == 1"/>
</Target>

As you can see I'm using another ItemGroup to define the assemblies that should be included in the testing. By convention I name all my test assemblies with the postfix Tests in order to be able to identify them easily.

I won't describe in detail all the attributes in here but you have to be careful with the test exit code.

The last line of the task contains an Output parameter. That is a variable that is going to be defined after the task runs. In this case the exit code is most important because it will indicate if the test has passed or not. Because the Gallio task does not update this value we need to check for it after running all the tests to be able to make the build fail if the tests fail.

The last line of the Test task uses the built in Error task to generate an error only when the ExitCode equals one indicating that the testing has failed.

Please follow the links to read more about MSBuild and MBUnit. Part II shows how to version our files using the version number from the repository and copy them to a different location. Go to MSBuild Part II. Enjoy.