MSTest v2: Test lifecycle attributes
This post is part of the series 'MSTest v2'. Be sure to check out the rest of the blog posts of the series!
- MSTest v2: Setup a test project and run tests
- MSTest v2: Exploring asserts
- MSTest v2: Data tests
- MSTest v2: Test lifecycle attributes (this post)
- MSTest v2: Create new asserts
- MSTest v2: Customize test execution
- MSTest v2: Execute tests in parallel
- MSTest v2: Testing against multiple frameworks
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]
.
[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.
[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.
[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 executedClassCleanupBehavior.EndOfClass
: Called after all tests of the class are executed
You can customize the global behavior by using the assembly attribute ClassCleanupExecution
.
[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.
[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!