This post is part of the series 'MSTest v2'. Be sure to check out the rest of the blog posts of the series!
Test projects often require setup before tests run and cleanup afterward. For example, you might need to set a global configuration or delete temporary files after a test run. This is especially useful for integration tests.
MSTest v2 provides a way to declare methods that the test runner calls before or after running tests. Here's how to 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. You can also use the class constructor for initialization in simple cases. By default, the method decorated by [ClassCleanup] is called after all tests in the assembly have 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()
{
}
}
When the class is inherited, you can use the InheritanceBehavior enum to control how class initialization and cleanup methods behave in derived 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 runs after all tests in the assembly have executed. You can trigger it earlier using the ClassCleanupBehavior enumeration.
ClassCleanupBehavior.EndOfAssembly: Called after all tests of the assembly are executedClassCleanupBehavior.EndOfClass: Called after all tests of the class are executed
You can set the default behavior for all classes using the ClassCleanupExecution assembly attribute.
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 each test, so you can use the parameterless constructor for initialization. If the class implements IDisposable, Dispose is called automatically after each test.
Alternatively, you can use MSTest-specific attributes, which are less idiomatic in .NET but still widely used. 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!