Testing Your Web Application With IIS Express and Unit Tests

Tags: IIS Express, Unit Test

After I read Scott Hanselman's blog post where he mentions how to launch IIS Express from the command line I thought it should be simple to integrate that into my tests so I can test the full path of requests hitting the web application. You will need to install Web Matrix in order to have access to IIS Express. Rumor has it that it will be available as a separate install later, but for now Web Matrix is a requirement. You can download it here.

In this post I'll go through the steps I went through to get it running. I'm not saying this is the best way, but it works for me.

It's one thing to get IIS Express running from the command line, but you need to have some content to serve for the requests in your tests. So you will need to make sure that the web application is built when you run your tests, so you don't test against an old version. The simple wey to do this is to add a reference, but that isn't really practical, since you don't need to reference the web site, you just need to make sure that it is built and running when you are sending your requests. A better way is to specify project dependencies, by right clicking on your test project in the Solution Explorer. Select the Project Dependencies line. This should bring up a dialog with your test project at the top and the other projects in your solution below. Check the box next to your web application to indicate that your test project depends on it. This will ensure that the web application is built before your test project.

If you are developing a normal web site it should be no problem with a normal build, but if you are using an MVC application, you will need to package it as part of the build. By default the projects created in Visual Studio have Build as their default build target (if you don't know what a build target is search for 'msbuild targets' in you favorite search engine, it's beyond the scope of this post to explain it). You will need to change your project file so that it builds and then packages the MVC application. The easiest way to do this is to right click your MVC project and select Unload Project. The right click the grayed out project and select Edit. This should bring up your build file, which is just XML. The root node should look something like this:

XML

<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

As you can see the default target is Build. Change the line so it looks like:

XML

<Project ToolsVersion="4.0" InitialTargets="Build" DefaultTargets="Package" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

The Package target is the target that is responsible for packaging the application. It is declared in some default target files for ASP.NET MVC that you don't need to worry about. What you have just done is change the default build behavior of the MVC application so that it builds the application and then packages it.

By default the MVC application will create a folder with the files that go into the package at /obj/[Debug|Release]/Package/PackageTmp relative to your MVC project's root. If you change that location you will need to change the location for your tests accordingly.

While you are configuring your build file you may want to add a property to prevent the package file from using tokens to replace your connection strings. These are added so that you can deploy your site with configurable parameters, but are a pain when you run the package files directly. This is certainly going to be a problem if you are using config file tranformations. To prevent the package from containing tokens instead of your connection strings, add the following to your build script properties:

XML

<AutoParameterizationWebConfigConnectionStrings>false</AutoParameterizationWebConfigConnectionStrings>

These files are the ones that you want to use as your site and have as the root for your IIS Express instance that your tests will be targeting.

To get your instance of IIS Express running and targeting the newly built site you will need to start it up and specify the root of the site as well as which port you want to use. This is what Scott Hanselman explained how to do from the command line in his post. Here we will be doing it as part of the test setup.

The following code samples use NUnit as the test framework, but there is not blockin you from using the xUnit or MsTest frameworks. The code to launch IIS Express is the same.

In your test setup method you will want to start a thread which runs the IIS Express process. I do it like this:

C#

private Process _iisProcess;

[TestFixtureSetUp]
public void Setup()
{
	var thread = new Thread(StartIisExpress) { IsBackground = true };

	thread.Start();
}

private void StartIisExpress()
{
	var startInfo = new ProcessStartInfo
		{
			WindowStyle = ProcessWindowStyle.Normal,
			ErrorDialog = true,
			LoadUserProfile = true,
			CreateNoWindow = false,
			UseShellExecute = false,
			Arguments = string.Format("/path:\"{0}\" /port:{1}", AppLocation, Port)
		};

	var programfiles = string.IsNullOrEmpty(startInfo.EnvironmentVariables["programfiles"])
						? startInfo.EnvironmentVariables["programfiles(x86)"]
						: startInfo.EnvironmentVariables["programfiles"];

	startInfo.FileName = programfiles + "\\IIS Express\\iisexpress.exe";

	try
	{
		_iisProcess = new Process { StartInfo = startInfo };

		_iisProcess.Start();
		_iisProcess.WaitForExit();
	}
	catch
	{
		_iisProcess.CloseMainWindow();
		_iisProcess.Dispose();
	}
}

What the code does is start up a separate thread for IIS Express and the start the web server process. There are a couple of things to note. The first is the arguments passed to the process start. The path is the path to your packaged MVC files mentioned above, so you will need to set the AppLocation variable. The port is the port number you will be running the site on, it can be set to any valid port number (like 12345). Another thing is the location of IIS Express. It gets installed as part of Web Matrix as a 32 bit application. This means that if you are running on a 64bit system, you won't be using the same path as a 32 bit system. Fortunately the ProcessStartInfo class gives you easy access to these folder locations in the EnvironmentVariables property.

All there is to do now is to start up the web server, which the test setup will now do. The server should now be running in a window which lets you track request (not strictly necessary when testing). The web server will now respond to incoming requests at the localhost address on your chosen port as if you were running a 'real' IIS server. This means that you can send HTTP requests to it from your tests, like so:

C#

[Test]
public void WhenRequestingDefaultPageThenGetResponseWithCode200()
{
	var request = (HttpWebRequest)WebRequest.Create("http://localhost:12345/default.aspx");

	var response = (HttpWebResponse)request.GetResponse();

	Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}

Once you have finished your tests you will want to shut it down again, which you can do like this:

C#

[TestFixtureTearDown]
public void Teardown()
{
	_iisProcess.CloseMainWindow();
	_iisProcess.Dispose();
}

When the web server was started we created a reference to it, which makes it easy to shut it down and dispose of it. That's all there is to running your tests against an IIS Express instance.

Latest Tweets