MSTest v2: Test lifecycle attributes

 
 
  • Gérald Barré

This post is part of the series 'MSTest v2'. Be sure to check out the rest of the blog posts of the series!

In a test project, some tests may have pre-conditions. You may also do some cleanup. For instance, you need to set a global configuration, or to delete some files after a test run. This may be more useful for integration tests than for unit tests.

MSTest v2 provides a way to declare methods to be called by the test runner before or after running a test. Here's how to use declare them:

#Initialize/Cleanup by assembly

The method decorated by [AssemblyInitialize] is called once before running the tests of the assembly. The method decorated by [AssemblyCleanup] is called after all tests of the assembly are executed. These methods can be located in any class as long as the class is decorated by [TestClass].

C#
[TestClass]
public class Initialize
{
    [AssemblyInitialize]
    public static void AssemblyInitialize(TestContext context)
    {
        Console.WriteLine("AssemblyInitialize");
    }

    [AssemblyCleanup]
    public static void AssemblyCleanup()
    {
        Console.WriteLine("AssemblyCleanup");
    }
}

#Initialize/Cleanup by class

The method decorated by [ClassInitialize] is called once before running the tests of the class. In some cases, you can write the code in the constructor of the class. The method decorated by [ClassCleanup] is called after all tests from all classes are executed.

C#
[TestClass]
public class TestClass1
{
    [ClassInitialize]
    public static void ClassInitialize(TestContext context)
    {
        Console.WriteLine("ClassInitialize");
    }

    [ClassCleanup]
    public static void ClassCleanup()
    {
        Console.WriteLine("ClassCleanup");
    }

    [TestMethod]
    public void Test1()
    {
    }
}

In case the class is inherited, you can use the InheritanceBehavior enum to customize the behavior of the class initialization and cleanup methods in the child classes.

C#
[TestClass]
public class TestClass1
{
    [ClassInitialize(InheritanceBehavior.BeforeEachDerivedClass)]
    public static void ClassInitialize(TestContext context)
    {
    }

    [ClassCleanup(InheritanceBehavior.None)]
    public static void ClassCleanup()
    {
    }
}

You can also customize when the cleanup method is called. By default the cleanup method is called after all tests of the assembly are executed. You can call is earlier by using the ClassCleanupBehavior enumeration.

  • ClassCleanupBehavior.EndOfAssembly: Called after all tests of the assembly are executed
  • ClassCleanupBehavior.EndOfClass: Called after all tests of the class are executed

You can customize the global behavior by using the assembly attribute ClassCleanupExecution.

C#
[assembly: ClassCleanupExecution(ClassCleanupBehavior.EndOfClass)]

[TestClass]
public class TestClass1
{
    [ClassCleanup(ClassCleanupBehavior.EndOfAssembly)]
    public static void ClassCleanup()
    {
        Console.WriteLine("ClassCleanup");
    }

    [TestMethod]
    public void Test1()
    {
    }
}

#Initialize/Cleanup by test

The test runner creates a new instance of the class for every test. This means you can also use the parameterless constructor to initialize your tests. If the class implements IDisposable, the IDisposable.Dispose method will be called after each test.

You can also use the less .NET-idiomatic method which consists of using the MS Test attributes. The method decorated by [TestInitialize] is called before running each test of the class. The method decorated by [TestCleanup] is called after running each test of the class.

C#
[TestClass]
public class TestClass1 : IDisposable
{
    // 1. Called once before each test
    public TestClass1()
    {
        Console.WriteLine("ctor");
    }

    //  2. Called once before each test after the constructor
    [TestInitialize]
    public void TestInitialize()
    {
        Console.WriteLine("TestInitialize");
    }

    [TestMethod]
    public void Test1()
    {
        // 3.
    }

    // 4. Called once after each test before the Dispose method
    [TestCleanup]
    public void TestCleanup()
    {
        Console.WriteLine("TestCleanup");
    }

    // 5. Called once after each test
    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }
}

#Execution log

Here's the execution log. I think this is much clearer than long sentences!

AssemblyInitialize   (once by assembly)
  Class1Initialize   (once by class)
    Class1.ctor      (before each test of the class)
      TestInitialize (before each test of the class)
        Test1
      TestCleanup    (after each test of the class)
    Class1.Dispose   (after each test of the class)

    Class1.ctor
      TestInitialize
        Test2
      TestCleanup
    Class1.Dispose
    ...
  Class2Initialize
      ...
  Class1Cleanup      (once by class)
  Class2Cleanup
AssemblyCleanup      (once by assembly)

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub