Thinking about things such as optimal solution structure might seem insignificant at first. Why not to just add a few projects to the solution and forget about it?! The answer is sure, why not… don’t regret though spending lots of your precious time when your project will grow and require closer attention - exactly at the time when one mindful architect would start thinking about continuous integration. Here is the quote from Wikipedia that we will keep in mind:
“Continuous integration – the practice of frequently integrating one’s new or changed code with the existing code repository – should occur frequently enough that no intervening window remains between commit and build, and such that no errors can arise without developers noticing them and correcting them immediately.” – Wikipedia
Now, let’s agree on what do we really want to achieve step-by-step. First thing’s first:
- Integration of unit (and integration) tests into the build process
- Seamless integration with build server
- Management of version numbers
- Integration with NuGet galleries (repositories)
- And finally, enabling the continuous integration (isolated to the current solution)
I would like to stress that based on my professional experience it’s extremely important to bring some order into the structure of your solution before going into solving any of the mentioned points towards continuous integration.
It’s worth mentioning which tools am I going to be relying on. Most of them are standard ones starting from source control system to command-line shell:
- Development environment - Visual Studio 2012⁄13
- Programming language - C#
- Source control system - Team Foundation
- Build system - MSBuild
- Command-line shell & automation scripting - Batch, Powershell
- Packaging system - NuGet
Integration of unit (and integration) tests into the build process
Let us start with the structure of your solution - projects, test projects, additional files. Here
you can see an example of the solution with a little bit of an order in it. Here are a few points
of reasoning behind this structure: test projects are isolated in it’s own virtual (and physical)
Tests (meaning that both
*.UnitTests projects are located
\Tests folder). Going forward it will help to automate running all tests during build
process. Test projects are split into two groups: unit and integration tests. There might be
different views on this subject. Here is mine: unit tests project contains only tests that do not
have explicit side effects like databases, files or web services that has to be there for such
tests to run. One could think of unit tests as tests that can be executed on the build server
without having additional setup arranged for it. On the other side integration tests project
contains such tests that might require additional setup like databases, files, etc. Integration
tests are typically slower to run and normally less reliable (due to it’s dependency to external
Projects themselves are located right under the solution node in this example. And I have to mention that strictly speaking it does not matter how you would arrange these projects.
Let’s now put this new structure of our solution into use. First of all we will try to find a more
or less natural way of controlling any build process with Visual Studio. That is
MSBuild. Here is
an example of
script for MSBuild (2012 refers to the version of Visual Studio used). Let’s go through some
logical parts in it.
First there is a definition of some properties: project name, path to
MSTest.exe and both unit
and integration test containers (paths to respective assemblies). Then there is the series of
actions dependent on each other so that if at least one of them fails - whole build fails. Here are
those in order of execution:
Now, let’s see how it’s possible to compile the solution with simple commands (just make sure that
MSBuild.exe is in your
According to the default verbosity level of the output you should see rather large output being produced:
If you would define
BuildDebug as a target, building process will end on building in debug mode,
Going forward this Build2012.proj script can be used as the key script on the build server. It can and should also be used in automation of building your solutions in general. Since this script is generic and only dependent on the structure of the solution (where to find test projects) it can be used for virtually any solution.
Management of version numbers
Version management is another point towards continuous integration. Not strictly required though.
In most cases version is controlled with assembly level attributes in
AssemblyInfo.cs files and
it might be handy to have a script changing it in a controlled way for you. Here you can find an
example such as this powershell script:
This script is capable of locating all files that needs to be changed, checking it out, changing
and prompt user with commit dialog with filled comment field waiting for you to accept it or
reject. Here is how it can be used (remember that there should be no pending changes to have it do
Depending on the parameter this script will increment major version (minor, revision and build versions will be set to zero), minor version (revision and build will be set to zero), revision version (only build will be set to zero) or a build version.
Integration with NuGet galleries (repositories)
NuGet is a free and open source package manager for the .NET Framework. NuGet is distributed as a Visual Studio extension, and integrated with SharpDevelop, and is included in the C# code snippet tool LINQPad. NuGet can be used from command line and automated via scripts. NuGet supports native packages written in C++. – Wikipedia
Package manager is a collection of software tools to automate the process of installing, upgrading, configuring, and removing software packages for a computer’s operating system in a consistent manner. – Wikipedia
There is an excellent article available about NuGet: Managing Dependencies with NuGet. It covers the dependency management problem, installing and using NuGet.
The idea is to be able to control the deployment of libraries. Yes, only libraries. There is a version of NuGet-based package manager available on Windows platform for applications called Chocolatey (that is trying to conceptually bring aptitude paradigm from linux world). It has not been yet released and has lots of limitations. I would still like to encourage you to try it out.
Here is the script that takes care of packaging libraries that has NuGet specification files and deploying it to supplied NuGet repository: DeployToNuGetRepository.ps1.
Documentation for NuGet specification files can be found
here. Here is an example of such a
specification for the
ClassLibrary1 project in our example solution which does not have any
dependencies other than standard framework assemblies:
Example of NuGet specification file for
ClassLibrary2 project that has a dependency on
ClassLibrary1 will look like following:
In order to initiate the deployment (after solution was build in release mode) the following command should be invoked:
This will deploy packages of our libraries into NuGet repository. These libraries can then be redistributed with using NuGet facilities. And will produce the following result:
Enabling the continuous integration
It’s a bit far to go yet for a strong continuous integration setup. But steps we went through can hopefully help getting there.
- MSBuild script: Build2012.proj
- Version management script: IncrementVersion.ps1
- NuGet packages deployment script: DeployToNuGetRepository.ps1
Author Roman Kuznetsov
License Roman Kuznetsov