This is a simple solution for monitoring and reporting unit testing results for apps written in C# 2.0 and stored in a SourceSafe database. I started writing the code and the article after reading some papers about command-line compilation in C# and command-line unit testing. I decided to write the code as part of an exercise with command-line tools, and also because I love unit testing, and I thought it would be great to experiment with a tool that could give me reports of my unit testing results. I'll be happy to listen to the readers' feedback - positive or negative - about the code and the article, and I'm willing to make improvements on the code while the readers respond to it.
At first, the solution looks like a continuous integration tool, but in fact, it's much simpler, and doesn't cover the key aspects of a continuous integration process, such as automatic deployment and production environment testing. There are many tools that do what this TestWatcher does and much more. You can look for robust and continuous integration tools such as CruiseControl.NET and MSBuild. This may seem like I'm reinventing the wheel, and that's true in a sense. But, as I said before, this is just an experiment. In addition, you don't need to create zillions of configurations. The code is very small, and you can configure and extend it as you wish. I think you can easily modify it to support automatic deployment and test coverage, for example.
In short, when you run Test Watcher, you are saying: "please check whether my projects on SourceSafe are passing their tests, and keep the in-charge people informed".
Test Watcher performs four main tasks, described in some detail:
- Connects to SourceSafe and gets the latest versions of the projects
Test Watcher connects to SourceSafe using the SS API. It passes the login and password to SS, and gets the latest version of the assigned projects (both the base project and the test project). The code is then downloaded to a configurable folder.
- Compiles the projects
Once we get the projects, we have to compile each of them. But first, we have to check which reference assemblies the project needs to be built with. For example, every test project needs a reference to the NUnit framework assembly. So, the project's configuration must inform Test Watcher to copy the NUnit framework assembly to the local build folder, so that it can be successfully compiled. We compile the C# classes through the C# command-line compiler, csc.exe (you might replace csc.exe by vbc.exe if you are trying to compile vb.net code). Each compilation step must produce an assembly DLL.
- Runs unit tests on the test projects through NUnit, and save the results
The compilation of the the target assembly (which holds the code being tested) must be followed by the compilation of the test assembly (which checks whether the target assembly passes or fails). So, the unit testing step must skip the projects which are the target projects, and run only on the test projects.
Each unit testing step produces an XML file, which is then transformed into a humanly-readable summary. This summary shows how many tests were performed, how many passed, how many failed, and shows the failure details.
- Sends email to project recipients, informing them of the test results
Finally, Test Watcher sends an email, reporting the summary tests, to the assigned project recipients. This is the final step and the main goal of the application.
The solution itself comprises of two projects: TestWatcherConsole and TestWatcherCore. The first is a Win32 console application, and basically controls the application flow and holds the configuration files, while the latter contains helpers that do the hard work. There are two more projects in the solution: Calculator and CalculatorTest. These projects don't take part in the application, but are kept together inside the solution just to test the application.
TestWatcherConsole is (guess what..) a console project. It has just one class,
Program, which contains the main application flow. It controls the Get Latest Version/Compile/Run NUnit/Send Mail process, according to the project's configuration. In each step, the TestWatcherConsole calls an appropriate method inside the TestWatcherCore assembly.
This project contains the helpers and the models for the application.
The helpers are
XMLHelper. They do the specialized work in the application.
The model classes are
WatchSolution represents a group (or a cycle) of
WatchProjects, which in turn are a representation of C# projects that must be compiled, tested, and then their results are sent by email.
The calculator example
We will be using two projects, Calculator and CalculatorTest, to test the application. Calculator performs the four basic arithmetic operations, and the CalculatorTest project just checks whether the operations are performed correctly.
First of all, we must have these projects on SourceSafe, so that they can be downloaded to a local folder to be compiled:
Now that we have the projects on SourceSafe, we should tell Test Watcher how to deal with our projects. We do this through the WatchSolutions.xml file:
C:\Arquivos de programas\NUnit 2.4.1\bin\nunit.framework.dll
C:\Arquivos de programas\NUnit 2.4.1\bin\nunit.framework.dll
Let's explain each part of the configuration file:
SSpath: The SourceSafe solution path, which holds all the contained projects. It must always start with a dollar ($) sign. In our case, it's $/CodeProject/TestWatcher.
WatchProjects: The array of
WatchProjects (see below) contained by the solution and which should be built. Those projects are Calculator and CalculatorTest. They are arranged in an order so that CalculatorTest must be compiled only after Calculator has been compiled.
Includes: An array of paths of references needed so that NUnit can run on the assemblies. In our case, there is just one assembly: nunit.framework.dll.
Name: The name of the project in SourceSafe. It will be used in combination with the solution's
AssemblyFile: The name of the output DLL file generated by the compiler.
IsNunitTarget: Boolean. Indicates whether the DLL of the project should be tested by NUnit. In our case, it's
false for the Calculator project and
true for CalculatorTest.
Includes: An array of paths of assembly references needed so that the project can be compiled.
MailRecipients: A list of email addresses who will receive the test results.
ReportOnlyInCaseOfFailure: Indicates whether the recipients will always receive the summary email, or will receive email only in the case of a failure.
You should still modify your app.config file before running Test Watcher.
<add key="ssDBIniPath" value="C:\vss\srcsafe.ini"/>
<add key="ssUser" value="Admin"/>
<add key="ssPassword" value=""/>
<add key="localPath" value="C:\temp\TestWatcher\"/>
value="C:\Arquivos de programas\NUnit 2.4.7\bin\nunit-console.exe"/>
<add key="smtpHost" value="smtp.gmail.com"/>
<add key="mailSender" value="firstname.lastname@example.org"/>
ssDBIniPath: The path for the SourceSafe database .ini file.
ssUser: The SourceSafe login that will be used by Test Watcher.
ssPassword: The SourceSafe password for the above user.
localPath: The temporary folder that will get the latest versions of the projects.
cscPath: The path for the css.exe file (C# command-line compiler).
nunitEXEPath: The path for the nunit-console.exe file (NUnit command-line executable).
smtpHost: The SMTP host used to send the summary e-mails.
mailSender: The e-mail address used to send the test results.
Now that you configured your app, and if everything went OK, you should receive an email like this:
- 2008-07-20: Initial posting.
Marcelo Ricardo de Oliveira is a senior software developer who lives with his lovely wife Luciana and his little buddy and stepson Kauê in Guarulhos, Brazil, and works for Curso de Ingles Online
He is often working with serious, enterprise projects, although in spare time he's trying to write fun Code Project articles involving WPF, Silverlight, XNA, HTML5 canvas, Windows Phone app development, game development and music.
Published Windows Phone apps:
CodeProject MVP 2012
CodeProject MVP 2011
Best Web Dev article of May 2012
Best Mobile article of January 2012
Best Mobile article of December 2011
Best Mobile article of October 2011
Best Web Dev article of September 2011
Best Web Dev article of August 2011
HTML5 / CSS3 Competition - Second Prize
Best ASP.NET article of June 2011
Best ASP.NET article of May 2011
Best ASP.NET article of April 2011
Best C# article of November 2010
Best overall article of November 2010
Best C# article of October 2010
Best C# article of September 2010
Best overall article of September 2010
Best overall article of February 2010
Best C# article of November 2009