After using XUnit for unit testing the past couple of years, I finally got a bit tired of the cut-and-paste-and-modify cycle of expanding test coverage for functionality I was building. I’ve used “row test” functionality in NUnit and MbUnit in the past, but hadn’t gotten around to finding out how to use them in XUnit until quite recently. The process I followed was relatively short: (1) Add the xunit.extensions dependency to my existing test assembly, (2) take a test that class that contained significant duplication and re-factor it to leverage one of the row testing attributes available.
In my case, the area I picked that would benefit from row testing was workflow testing. We implement our workflows as state machines with transition tables that define a starting state, an ending state, and the event that triggers the state change. I’d previously tested these workflows with one unit test per transition, with those three attributes (start state, end state, event) being the only thing different between them. This meant a single test that took these attributes as parameters should be sufficient to test transitions, and that the row testing attribute(s) would contain the actual values.
The Theory attribute supports a number of different data sources, including inline data, Excel data, and SQL Server data. I started with inline data believing it would be the simplest. But I wasn’t able to get that to work because the InlineData attribute of Theory only appears to support primitives (int, bool, string, etc). Our workflow events and statuses are classes with attributes that are static and read-only. From there, I moved on to try the PropertyData attribute. This attribute takes one string argument that needs to match the name of a property added to the test class that returns a collection of object arrays with one set of test parameters per entry.
Following that approach worked much better. The results display pretty nicely in ReSharper as well:
I’m still working on a code example of this to make available on GitHub, but here are a few links I found useful in getting up to speed with the additional capabilities of XUnit: