The Visual Studio ALM Rangers have just released a new version of the WCF Load Test tool. The tool has been maturing over the last 3 years and the occasion of a new release seems like a good time to post a walkthrough of how to use the tool.

What Does WCF Load Test Do?

WCF Load Test is a tool that auto-creates unit tests in your test projects. These unit tests can then be used to load test WCF services. It works by reading a log of the calls made to the WCF services and translating those calls into C# code. The tool can read WCF message logs which have been taken on the client or the service side. It can also handle ASMX services, even if there is no WCF client involved, which comes from the capability to process Fiddler2 traces.

You might think that generating code from a trace is just going to replay the same data over and over again in a load test. That could be a major limitation. To address this, the generated code also supports parameterisation of the data passed to the WCF services so that you can include your own data randomization code for a more realistic test.

The November 2010 update deepens support for existing .NET technologies. Based on high demand DataSet support has now been added. Support for duplex contracts has been improved. This release also brings some usability improvements. The wizard no longer locks your assemblies once they have been used. Finally, you will notice improved error reporting.

Generating a Unit Test

The tool just needs a WCF message log and the contract assemblies to be able to work. One way to do this is to run a client program that calls the WCF service which creates a message log. The message log represents the scenario you want to test. The WCF Load Test project item wizard makes this process straight forward by automating a few steps like changing the diagnostic settings in the config file and undoing the changes at the end.

The rest of this posting shows you how to generate a unit test that can be used to load test a WCF service. I am assuming you already have a WCF service and a client program which can be used to exercise the service.

The service we are using implements the following contract:

[ServiceContract]
public interface IArithmetic
{
[OperationContract]
int Add(int a, int b);

[OperationContract]
Response Subtract(Request req);
}

[DataContract]
public class Request
{
[DataMember]
public int A;

[DataMember]
public int B;
}

[DataContract]
public class Response
{
[DataMember]
public int Answer;
}

The Subtract operation uses DataContracts just to show how this is supported.

Step 1: Installing WCF Load Test

Just head over to http://wcfloadtest.codeplex.com/ and download “Version 3.0 (Beta) - Build 3.0.10.0903”. Included in the ZIP file, you can find an MSI called wcfuniten.msi. Double-clicking this installs the tool. It will add a new item for test projects into Visual Studio Team System 2008 (Professional, Development Edition, Test Edition or Team Suite) and Visual Studio 2010 Ultimate Edition.

Step 2: Create a Test Project

We start by creating a Test project. This release can only generate C# code which means a C# Test project is required.

clip_image002_2_212FB60B

Once the load test project has been created you can delete the UnitTest1.cs file that gets added, as you don’t really need it.

Step 3: Start the Wizard

We are now ready to start the wizard which will generate the unit test. To do this, right-click the load test project in the Solution Explorer and select Add -> New Test.

clip_image004_2_212FB60B

When you click OK the first screen of the wizard will appear:

clip_image006_2_212FB60B

Step 4: Run the Client Executable from the Wizard

Click Next to move to the next screen in the wizard. Type in or browse to the executable for the client that exercises your service.

clip_image008_2_212FB60B

Once you have entered a path to the executable, the wizard enables the Run button. Click the run button and the wizard edits the config file to make sure that it creates a suitable message log and starts your executable. Use your client to execute the scenario that you wish to capture in the message log and then exit the client. Remember to check that the service you want to test is already running.

If you already have a message log, which can come from either the client or the service side, you can supply the details on this screen. The usage notes document that comes with the tool describes the settings you need if you want to capture your own message log.

Whichever method you use to give the wizard the message log, the wizard parses the message log and then enables the Next button, click this to move to the next step.

Step 5: Set the Code Generation Options

The wizard shows you the list of distinct operations it has found in the message log. You can choose which operations you want to include in the unit test. If you choose to include transaction timers, the generated code will include a per-call timer that collects data on how long each call to the service takes. This information is collected, stored and displayed by the Visual Studio load test. You can also choose to have a separate unit test for each service call if you like.

Note that by default it will generate a single unit test that represents the entire scenario. In this example there will be a single unit test which calls Add and Subtract.

clip_image010_2_212FB60B

Step 6: Select the Contract Assembly

The next wizard screen is used to tell the wizard which assemblies contain the contract definitions required for the wizard to be able to generate the unit test code. If you are using a compile time proxy, you must supply the assembly containing the proxy - and any of its dependencies. If you only have a contracts assembly then that is what you need to supply. The code generated is slightly different depending on whether you have a proxy or not.

clip_image012_2_212FB60B

Use the Add button to add the necessary assemblies. This will enable the Finish button. Click Finish and the code will be generated and added to your Test project.

Here is a snippet from the generated code:

[TestMethod()]
public void WCFTest1()
{
// 15/09/2010 06:47:14
this.Add();
// 15/09/2010 06:47:14
this.Subtract();
}

private int Add()
{
int a = 10;
int b = 20;
this.CustomiseAdd(ref a, ref b);
_testContext.BeginTimer("WCFTest1_Add");
try
{
return arithmeticClient.Add(a, b);
}
finally
{
_testContext.EndTimer("WCFTest1_Add");
}
}

private Contracts.Response Subtract()
{
Contracts.Request req = new Contracts.Request();
req.A = 10;
req.B = 5;
this.CustomiseSubtract(req);
_testContext.BeginTimer("WCFTest1_Subtract");
try
{
return arithmeticClient.Subtract(req);
}
finally
{
_testContext.EndTimer("WCFTest1_Subtract");
}
}

You can see from this example that the main test method simply calls two methods. These two methods represent the two service calls that the client initiated. The bodies of those methods set up the parameters for the call and then call the service.

You will see that the parameters are firstly passed to another method, called CustomiseXXX. This is the method which has been generated in a separate partial class file. You can put any code you like here to amend the parameter values so that you can vary the data. The generated code actually does nothing and leaves your parameter values intact. You can tie the customization methods into the data-driven testing feature to drive the parameter values from a spreadsheet or a database table.

Step 7: Configure the Service Client

The last step to getting a working unit test is to set up the test to connect to the WCF service. The code to make this happen is in the same partial class file that contains the customization methods. It contains the InitializeTest method which creates the service proxies for all the required services, but as it stands it does not have enough information. You need to add an app.config file to the Test project which contains the client configuration. Usually, the config file is just copied from the client program used to exercise the service. You can then modify InitializeTest to load the relevant configuration.

Here is an example with the change (the addition of “Basic”). The name “Basic” refers to the endpoint configuration name in the app.config file:

[TestInitialize()]
public void InitializeTest()
{
System.Threading.Monitor.Enter(arithmeticProxyTable);
try
{
arithmeticProxyTable.TryGetValue(System.Threading.Thread.CurrentThread.ManagedThreadId, out arithmeticClient);
if (((arithmeticClient == null)
|| (((System.ServiceModel.ICommunicationObject)(arithmeticClient)).State == System.ServiceModel.CommunicationState.Faulted)))
{
// The following line may need to be customised to select the appropriate binding from the configuration file
System.ServiceModel.ChannelFactory<Contracts.IArithmetic> arithmeticFactory
= new System.ServiceModel.ChannelFactory<Contracts.IArithmetic>("Basic");

arithmeticClient = arithmeticFactory.CreateChannel();
((System.ServiceModel.ICommunicationObject)(arithmeticClient)).Open();
arithmeticProxyTable[System.Threading.Thread.CurrentThread.ManagedThreadId] = arithmeticClient;
}
}
finally
{
System.Threading.Monitor.Exit(arithmeticProxyTable);
}
}

The code above is slightly different if you gave the wizard a compile-time proxy to use instead of just a contract.

Step 8: Run Some Tests!

The unit test that the tool generated is now ready to be tested. Just run it as a unit test first to make sure it runs OK. Remember to check that the service you are testing is up and running. Once the unit test is running you can then go ahead and add it to a Visual Studio Load Test with the standard procedure for running load tests.

Summary

We have seen how to create load tests for WCF services by capturing message logs and turning them into executable code which can be run by the Visual Studio Load Test feature. If you want to explore the tool further there are other features which for example support testing ASMX services. The tool is not limited to one WCF service and can also generate tests that invoke multiple services.

Visual Studio ALM Rangers love to get your feedback. Please use the discussions tab on the CodePlex site to submit your feedback.

Written by Rob Jarratt