Enabling parameterized tests in MSTest using PostSharp

I have blogged about the shortcoming of Microsoft’s unit testing framework in the past. It has very good Visual Studio (and TYFS) integration out of the box but it seems that in order to use it I have to suffer lack of functionality I’m used to taking for granted when using any other .NET unit testing framework out there. ON the of feature I miss most is RowTest (Theory for you XUnit users). When using MSTest I want to be able to create a test that receive parameters. It shames me to have to tell a co-worker to write 10 (or more) different tests that test the exact functionality with differed conditions.

There is a way to run parameterized tests in MSTest namely data-driven tests the downside is that you have to create an external file to host the parameters making the test less readable to my taste. Another alternative is to use MSTest that comes with VS2010 and extend it – I wrote about it in a previous blog post.

I’ve decided to create another solution for those of you that do not use VS2010 and .NET 4 or do not want to extend the testing framework – using data-driven test and the power of PostSharp.

The incidents

  1. One test marked as a test class no parameters
  2. One test with the same name with parameters
  3. One simple RowAttribute to keep the parameters
  4. One PostSharp OnInvocation attribute to do all of the magic
  5. Mix & Run

The Test(s)

Because of MSTest limitation will need two functions with the same name. The first one without parameters will be used as a host test method to run and the second will contain the actual test code:

public class MyRowTests
public TestContext TestContext { get; set; }

[TestMethod, RowTest]
"Row", DataAccessMethod.Sequential)]
public void SimpleRowTest()


[Row(1, 2, 3)]
[Row(3, 2, 5)]
[Row(3, 4, 9)]
[Row(3, 4, 7)]
public void SimpleRowTest(int x, int y, int result)
Assert.AreEqual(result, x + y);

The first method is the one MSTest know and respect and we’re going to use it to run the second method. I’ve added DeploymentItem and DataSource attribute to run the xml file that is going to be generated with the data from the Row attributes.

Note: It is important that the deployment item would point to the relative path of the test project file from the solution file – this is one nasty bit of code and I wish I could find a way to throw it away.

Note: It is crucial that you have TestContext defined in the test class as well – otherwise MSTest won’t be able to access the test’s parameters:


This is a plain old C# attribute – nothing special, just a container to hold the row test data:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class RowAttribute : Attribute
private readonly object[] _rowParameters;

public RowAttribute(params object[] rowParameters)
_rowParameters = rowParameters;

public object[] Parameters
get { return _rowParameters; }

It’s marked to be used on a method and that it can be applied multiple times and that’s it./p>


This is where the magic happens! The attribute does two things:creates a xml data source file and run the method with the parameters. Inheriting from MethodInterceptionAspect enables hooking into two events – compilation of the class and when it runs:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class RowTestAttribute : MethodInterceptionAspect
private MethodInfo _methodToInvoke;

public override void CompileTimeInitialize(MethodBase method, AspectInfo aspectInfo)
base.CompileTimeInitialize(method, aspectInfo);

_methodToInvoke = method.DeclaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Single(info => info.Name == method.Name && info != method);

var rowAttributes = _methodToInvoke.GetCustomAttributes();

CreateDataSource(_methodToInvoke, rowAttributes);

public override void OnInvoke(MethodInterceptionArgs args)
var testContext = args.Instance.GetPropertyValue("TestContext");

var parameters = _methodToInvoke.GetParameters();

var arguments = testContext.GetParameterValues(parameters);

_methodToInvoke.Invoke(args.Instance, arguments.ToArray());
catch (TargetInvocationException exc)
// fix stacktrace
FieldInfo remoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic); // MS.Net

remoteStackTraceString.SetValue(exc.InnerException, exc.InnerException.StackTrace + Environment.NewLine);

throw exc.InnerException;

private string CreateDataSource(MethodBase testMethod, IEnumerable customeAttribute)
var projectFileName = PostSharpEnvironment.Current.CurrentProject.EvaluateExpression("{$MSBuildProjectFullPath}");
var projectPath = Path.GetDirectoryName(projectFileName);
var filename = Path.Combine(projectPath, _methodToInvoke.Name + ".xml");

using (var sr = new XmlTextWriter(filename, Encoding.ASCII))
foreach (var rowAttribute in customeAttribute)

for (var i = 0; i < rowAttribute.Parameters.Length; i++)
sr.WriteStartElement("value" + i);



return filename;

There are three main functions:

  1. CompileTimeInitialize – that get called when the code compiles and is responsible to create the XML file – remember we need it before the test runs
  2. OnInvoke – called when the test runs. Reads the data from the data source and convert the parameters before running the second (parameterized) method
  3. CreateDataSource – you’ve guessed it – this is where we create the xml file – simple and dirty… I use PostSharp’s EvaluateExpression to find where the project’s file is – remember this bit runs on compile so no tricks using reflection could be used to find the target assembly.


Simple methods I use in the RowTestAttribute – just in case you’re wondering:

public static class Extensions
public static IEnumerable GetCustomAttributes(this MethodBase method) where T : Attribute
return (T[])Attribute.GetCustomAttributes(method, typeof(T));

public static T GetPropertyValue(this object instance, string propertyName)
var propertyInfo = instance.GetType().GetProperty(propertyName);
return (T)propertyInfo.GetValue(instance, null);

public static IEnumerable GetParameterValues(this TestContext context, ParameterInfo[] parameters)
for (var i = 0; i < parameters.Length; i++)
var parameterType = parameters[i].ParameterType;
var inputData = context.DataRow["value" + i];

yield return Convert.ChangeType(inputData, parameterType);

Running the test

MSTest force me to run the empty parameter-less method. Running the test from the beginning of this post will result in the following:


How cool is that – The “test” is actually 4 tests run separately and one of them failed – with a clear error message. And  there’s more clicking on the test we get to see the full error message:


In fact I was so impressed with how it works that I put it to us at work despite the fact that it’s not finished yet.

Is it done?

Not yet – I would really like to throw away the DeploymentItemAttribute and if I can get away with it the DataSourceAttribute. I do use it daily and it feels just wrong.

I’ve tried creating the attributes in runtime – using PostSharp but Visual Studio was not fooled – probably because DTE is used to collect these attribute and not reflection.

By publishing this post I was hoping to achieve two goals:

  • Help other lost souls such as myself that are forced to use MSTest but wish they had the ability to run RowTests – BTW you’re welcome
  • Get feedback, suggestions and ideas how this nifty idea can be improved

And please let me know if you put this code to use – that’s what the comments are for


Happy coding…

5 thoughts on “Enabling parameterized tests in MSTest using PostSharp”

  1. I actually used it as a reference – the problem with DaTest that it still runs only one test – so if one of the “test cases” fails the whole test fail while the way outlined in this article runs each case as a different “test”

  2. Hi, I'm working on making a suite of tests easily run against multiple databases and just ran across this post. This technique looks very promising – but I'm curious what you've learned about it in the last two years. Did it work well? Any pitfalls to beware of?

  3. Hi Rob,

    I've been using the method described in this post with some success but my conclusion is that if you need to use parameterized unit test – choose a framework that have a good support for it. There's no substitute to the ease of use of real support and no amount of tinkering can achieve what can be easily done with NUnit/XUnit and others.

    If for some reason you have to use MSTest due to one of it's key strengths – interation with TFS or deployment items – then this is the closest I managed to get to supporting parameters in tests.

    There's another way to add functionality to MSTest – it only works for versions from .NET 4 – I wrote about it at:http://blog.drorhelper.com/2011/01/how-to-add-rowtest-support-to-mstest.html

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s