Extending MSTest V2

APIs are assets. As developers we learn them, write to them, and – if the API are extensible – we grow them. An extensible API removes barriers to introducing new abstractions closer to our own domains. Once such abstractions are in place, they in turn allow us to work with the underlying framework in a more fluent manner. Extensibility therefore has been a goal for the MSTest V2 Test Framework API.

MSTest V2 lends itself to being extensible at various points:
Attribute extensions
TestProperty has been the way to add any description to a test method. It takes two strings as name/value pairs – general enough, but also verbose, and a little error prone (easy to misspell the strings and end up with multiple names/values).

MSTest V2 allows TestProperty to be extended, allowing you to write, and subsequently use, strongly typed attributes. This is both more convenient and robust. Here is the RFC describing the approach: RFC 001- Framework Extensibility Description Attributes.

Assertion extensions
MSTest V2 comes with a set of in-built assertions. While general enough to be used in a variety of scenarios, this generality also renders them verbose. When writing multiple, and complex, assertions in a test, this verbosity can overwhelm and obscure intent – leading to a maintenance challenge.

MSTest V2 allows the in-built assertions to be extended – to be lifted closer to the domain under tests. This at once makes them more readable and maintainable. Here is the RFC describing the approach: RFC 002- Framework Extensibility for Custom Assertions.

Execution extensions
The default flow for executing a test in MSTest V2 involves creating an instance of a TestClass and invoking a TestMethod in it. While this might serve most purposes, what if you want finer control – what if you want the test to run only on the UI thread? What if you want the test to be executed multiple times? There are many such cases where you would want execution-control.

MSTest V2 allows you to extend, and control, test execution at a couple of levels:

  • TestMethod level – this allows you to create your own, named, version of the [TestMethod] attribute, and take over execution for that test.
  • TestClass level – this allows you to create your own, named, version of the [TestClass] attribute and take over execution for all tests within the class.

Here is the RFC describing the approach: RFC 003- Framework Extensibility for Custom Test Execution

Data driving extensions
Tests can be driven with data provided inline (with the DataRow attribute), or with data provided from an external source like a file, database, etc. Data provided with the DataRow attribute need to be constants only and cannot be shared across tests. On the other hand, data coming from a file or a database might not be the appropriate solution for many use cases. What if you want the data to come from another method and would like that it be shared across tests?

MSTest V2 allows you to implement the ITestDataSource interface to then provide data in whatever way you choose to the test. Thus, a test can not only have a custom data source, but also that custom data source can be used in multiple tests. Here is the RFC describing the approach: RFC 005- Framework Extensibility for Custom Test Data Source

The following image summarizes the extensiblity points described above:

By itself, MSTest V2 is feature rich, and general. However, extending the framework appropriately will allow you to express your tests in language closer to your specific domain model. That is when the true power of MSTest V2 is unleashed.

In this post we looked at specific extensibility points supported by MSTest V2. In subsequent posts we will look at concrete examples illustrating these extensibility points.
Stay tuned!