ClassInitialize, ClassCleanup, and Sharing Data Across Tests in XUnit2

So far in this series on migrating from MSTest to XUnit, we have looked at:

In this post, we will look at how we can share setup and cleanup code across tests in a test class in XUnit. MSTest allows you to define shared setup and cleanup code for an entire test class by using methods decorated with the ClassInitialize and ClassCleanup attributes. Unlike their counterparts, TestInitialize and TestCleanup, methods decorated with these class-level attributes are executed just once per class, rather than once per test in the class. Using these class-level attributes, we can execute code, generate fixture objects, and load test data that can be used across all tests in the class without having the overhead of repeating this for every test in the class. This is useful when that initialization or cleanup is expensive, such as creating a database connection, or loading several data files.

As we have seen so far, XUnit is light on decorating non-test methods with attributes, instead relying on language syntax that mirrors the purpose of the code. In the case of TestInitialize and TestCleanup, XUnit uses the test class constructor and IDisposable. It should come as no surprise that this pattern is also used when it comes to class-level initialization and cleanup.

IClassFixture<T>

There are two parts to shared initialization and cleanup in XUnit: declaring what shared items a test class uses, and referencing them within test methods.

To declare specific setup is required, a test class must be derived from IClassFixture<T> for each shared setup/cleanup. The T in IClassFixture<T> is the actual type responsible for the initialization and cleanup via its constructor and IDisposable implementation.

The XUnit test runner sees that your test class is deriving from IClassFixture<MyFixture> and ensures that an instance of MyFixture is created before your tests are run and disposed of when all the tests are completed. I really like this approach over the MSTest equivalent, as it moves the setup and initialization from being about the test class to being about the test fixture, the thing being setup. You can even have more than one fixture, so if you use two databases in your tests, you can have one fixture for each database and explicitly specify the use of each. It also means that you can set things that are supposed to be immutable for the duration of tests to be readonly and enforce that immutability. This is even clearer when referencing fixtures in tests.

As shown in the preceding example, to reference a test fixture in your test class methods, you just need to add a corresponding argument to the constructor and XUnit will inject the fixture. You can then use the fixture, and assign it or something obtained from it to a member variable of your class. Not only that, but you can mark that member as readonly and be explicit about what tests can and cannot do to your test state. Personally, this approach to shared initialization and cleanup feels much more intuitive. I can easily reuse my initialization and setup code without cluttering my test classes unnecessarily, and I can be explicit about the immutability of any shared state or setup.

And that is it; now you not only know how to share repeatable setup across tests (as provided by TestInitialize and TestCleanup in MSTest), but also how to do the same for setup across the whole test class (as MSTest does with ClassIntialize and ClassSetup).

But, what of AssemblyInitialize and AssemblyCleanup? Well, that's probably a good place to start in the next post. As always, you are welcome to leave a comment letting me know how you are liking this series on migrating to XUnit, or perhaps bringing up something that you'd like me to cover.

TestContext Equivalence in XUnit2, or How Do I Write Output in XUnit2?

So far, in discussing the migration of MSTest to XUnit2, I have only touched on the basics. First, I covered using the XUnitConverter to make the transition a little easier, then I provided an overview of how the basic MSTest concepts tests, test initialization, and test cleanup were supported. In this post I want to look at the confusing dumping group that is TestContext. My goal with these posts is to provide useful search results for those looking for information on XUnit, especially when migrating from MSTest. For a moment though, let me rant about TestContext.

I am sure that there are people out there who totally get all the values and functions TestContext provides; however, other than writing log messages, I have found the TestContext properties wildly confusing and unhelpful. I somehow doubt I am alone. Not only that, but the inconsistent ways a method gets access to the TestContext dependent on whether it is an instance method or a static method makes things confusing1.

TestContext Properties

TestContext Properties

TestContext Methods
TestContext Methods

Looking at the documentation from MSDN (shown above), it should be clear to anyone that TestContext is trying to do a lot of different things. There are methods in there for outputting things to the test trace messages, adding results files, and running timers, and properties for getting all sorts of information from directories for results, to the name of the test, to things related to data driven tests. Overall, it is convoluted and confused; do you know the difference between ResultsDirectory, TestResultsDirectory, and TestRunResultsDirectory? Even after working with MSTest for nearly 10 years, I could not begin to tell you. In my opinion, TestContext does too much and is almost always unintuitive to use, so how does XUnit tackle these things?

Well, first of all, XUnit does not even begin to replace the timer stuff because, well, there are plenty of timer options available in the .NET framework, so just use one of them.

Second, XUnit manipulates the current directory when running tests, so the location retrieved from Environment.CurrentDirectory will be where the tests are running and where test data will live. We will focus on data-driven testing in another post, but suffice to say that you do not need to decipher pages of documentation or debug tests to understand where to find your test data or where to output your test results (if you have something to output, of course).

Finally, if you want to write to the test output, XUnit provides an interface that you can inject into your constructor for doing just that and only that; ITestOutputHelper.

ITestOutputHelper

Since the XUnit documentation is very helpful on how to use this interface, I won't go into great detail here. However, for those looking to replace TestContext.WriteLine, this is what you need to do.

The test runner observes from the signature of the class constructor that it requires the ITestOutputHelper interface and injects it, making it available throughout the test execution, including during the Dispose method, if present.

Next time, we will take a look at how XUnit tackles sharing initialization across multiple tests. In the meantime, if you are finding these posts useful or have any questions, please leave a comment.


  1. a property called TestContext with public getter and setter for instance methods; or passed as a parameter for static methods 

TestMethod, TestInitialize, and TestCleanup in XUnit2

In the last post, I briefly described how to automatically migrate your MSTest tests to XUnit by using the XUnitConverter utility. Of course, nothing is ever that simple; MSTest has some concepts that XUnit expresses very differently1 like how to share code between tests whether that is setup, fixtures, cleanup, or data. Some of these concepts are implemented differently enough that automating the migration from one to the other would be very difficult if not impossible. However, some of it really is that simple. Before we look at the difficult examples, I thought it would be useful to illustrate how some of the simple concepts map from MSTest to XUnit using an example2.

So, let's look at an MSTest example (contrived, of course):

Clearly, I cheated by not actually making the tests do anything, but the content of the test methods is mostly irrelevant; you set some stuff up, you do something, and you assert a result–it's all the same regardless of the test framework. However, this is a simple example of a test class written for the MSTest framework. There are attributes to tell the framework that the class is a test class, which methods inside of it are test methods, and which methods should be called before and after each test. In this case, our test initialization creates a stream, which is then disposed of in the cleanup method; each test method would get sandwiched in the middle.

After converting to XUnit with the converter tool, the same class will look something like this:

There are a few things that happened.

  1. The class no longer has an attribute. XUnit knows the class is a test class because it contains tests3.
  2. The tests are decorated with a [Fact] attribute, which is equivalent to [TestMethod].
  3. The [TestInitialize] and [TestCleanup] attributes are gone. Instead, the class constructor is used for test initialization and the Dispose method along with deriving from IDisposable indicates that there is test cleanup code.

Overall, I love how the XUnit syntax works with C# syntax and .NET idioms in declaring tests. Not only does this reduce the ceremony around defining tests by reducing the various decorators, but it also allows for cleaner coding practices. For example, we can now correctly mark our memory stream member variable as readonly.

By relying on C# syntax and standard interfaces in this way, the lifecycle of a test is clearer too; XUnit will construct and dispose the class for each test in the class, making it easy to see how each test will run. This idiomatic way of declaring tests allows for separation of concerns, keeping test classes light and focused. This will be illustrated when we later look at other concepts in MSTest like [ClassInitialize] and [ClassCleanup], TestContext, and [DeploymentItem], and how XUnit tackles the problems these concepts solved.


  1. and for good reasons, IMHO 

  2. XUnit documentation has a handy table but I don't think it's as illustrative as it could be 

  3. why MSTest did not make assumptions like this, I do not know 

Migrating from MSTest to XUnit 2

We recently migrated most of our testing from the MSTest framework1 to XUnit 2 (from here on in, I will be referring to this as just XUnit). This was not a change taken lightly since it touched a lot of files, but we were motivated by a number of XUnit features, including reduced need to attribute test classes, easier data-driven tests, and parallel test execution.

Sadly, if you try this you may discover as we did that the XUnit documentation is equal parts super helpful and woefully lacking, depending on what you are trying to do. After hearing yet another colleague lament how hard it was to find information on some feature or other of XUnit, I thought it might be a good idea to document some of the things I have learned and hopefully, introduce yet another helpful XUnit resource to the Internet2.

For those not familiar with XUnit, the basics are pretty easy. In fact the existing XUnit documentation includes a handy table mapping concepts in other test frameworks to their XUnit equivalents. You can check that table out for details, but basically, through the use of attributes, constructors, IDisposable, and other interfaces, XUnit uses what I would describe as a more natural approach than other frameworks to concepts like tests, test initialization and cleanup, and test fixtures. Of course, this means that migrating from one framework to XUnit involves a bunch of file editing, but fear not for there is help.

XUnitConverter

The bulk of the migration was made a lot easier by using the XUnitConverter, a tool available in the dotnet/codeformatter GitHub repository. Although it does not take care of everything (beware if you have multiple test classes per file) and, depending on your preferred code format, can mess your formatting up a bit, but it does make the migration a lot easier.

The XUnitConverter runs against a csproj file. You can use PowerShell to recurse your solution and process all your projects like this:

Once the converter has done its thing, it is easy to identify further changes by using the compiler (things don't like to build if something did not work right). Although most things get converted with ease— [TestMethod] becomes [Fact], [TestInitialize]  becomes a constructor, complex tests will need a little more assistance to fully migrate. For example, XUnit uses interfaces and fixture classes to replace the kind of shared initialization and cleanup that MSTest provides via the [ClassInitialize] and [ClassCleanup]. We will start tackling these issues next time.


  1. Version 1 of MSTest, not the new and improved MSTest version 2 

  2. I would like to document my anecdotal information before I even consider tackling something a little more structured like contributing to the official documentation 

Being Grateful Is Good For You

Being grateful—for what others do, for good fortune, for what you have—is good for you. It makes you happier, helps you sleep better, and boosts your immune system. Being grateful is a good way to live and when you thank someone else for what they have done for you, I believe it fosters relationships, builds community, and encourages others to do the same.

I learned about the concepts behind journaling gratitude at my first KalamazooX when Elizabeth Naramore1 discussed her own gratitude journal. Around the same time, a Facebook friend started recording five things a day for which they were grateful. Looking back, this was the period when I started to acknowledge that I had unaddressed problems with depression, anxiety, and self-worth. Being grateful seemed like an easy place to start, so I gave it a try.

At different times, I recorded my gratitude using Facebook, Twitter, a physical journal, and my blog. Eventually, it started feeling stale or false; I was being thankful for inanimate or generic things like coffee, friends, or sunshine. Don't get me wrong, these are all fantastic things, but stating gratitude for coffee felt like my goal had become writing about gratitude than actually feeling grateful.

"…people are not so keen on just handing out personal information like their home address without at least knowing why."

Sometime before a visit to Boston, I had read about a man who set out to send one "thank you" note a day for a year. The idea of writing to people and thanking them directly was appealing. While in Boston, we visited the Isabella Stewart Gardner Museum, and there I bought a box of postcards that I thought would suit this purpose. It took another two years and a move to Texas before I actually got started.

It has now been three weeks since I started; I have sent 20 cards, and have another four ready to go this week. Writing them is cathartic for me and I get a little excited to mail each one. I keep a list of the people I intend to write to and make sure to keep track of those to whom I have already written. Each day, I send one card, write one or two more, and send a message or two over the Internet to get addresses. However, it turns out that some people are not so keen on just handing out personal information like their home address without at least knowing why. This seemed odd to me at first and I felt untrusted. In addition, I felt a deep reluctance to explain why. It seemed I felt the value of this project was lost if the postcard was not a surprise. Of course, that is ridiculous; not only do people have every right to know why I would want their address, but if the surprise of receiving the card itself were the value, what would be the point of writing anything on the card?

So, I write this blog entry, in part, to provide an explanation for people when they ask why I need their address. That said, I also write it as encouragement to others who might be considering the start of their own gratitude project. Being grateful is powerful on its own, yet the responses I have received to messages I have sent have been wonderful, humbling, and kind. People are amazing, so tell them; the more you thank others for their impact on your life, the more you will be surprised by your impact on theirs.


  1. IIRC