In previous blog posts about unit testing, we illustrated how to create unit tests with MSTestv2 by marking a class with the TestClass attribute and test methods with the TestMethod attribute. In this blog post, we will introduce some other attributes that can be used, which are often referred to as “test life cycle” attributes.
This blog post is part of a series on unit testing:
1. Introduction to unit testing
2. Creating unit tests using the MSTestv2 framework in Visual Studio
3. Using isolation frameworks
4. Writing testable code
5. FluentAssertions
6. Data-driven tests
7. Test life cycle attributes
8. Using files in unit tests
Test life cycle attributes can be useful in situations where some common logic must be executed before or after a test is executed (e.g. creating a connection, or doing some cleanup). This can, for instance, be the case when implementing integration tests.
MSTestV2 supports the following Initialize/Cleanup attribute pairs:
- AssemblyInitializeAttribute and AssemblyCleanupAttribute
- ClassInitializeAttribute and ClassCleanupAttribute
- TestInitializeAttribute and TestCleanupAttribute
Now let’s take a closer look at how you use these attributes!
AssemblyInitializeAttribute
The AssemblyInitializeAttribute attribute can be used to identify a method that should be executed before any test in the assembly runs:
- The method must be part of a class annotated with the TestClassAttribute attribute.
- This attribute can only be applied to one method in an assembly.
- The method to which this attribute is applied must be static and public, have a single parameter of type TestContext, and must not return a value (or, when using async-await, return a Task).
- This method will be executed before any method annotated with the ClassInitializeAttribute, TestInitializeAttribute or TestMethodAttribute attribute.
AssemblyCleanupAttribute
This attribute can be used to identify a method that should be executed after the tests in the assembly have been executed:
- The method must be part of a class annotated with the TestClassAttribute attribute.
- This attribute can only be applied to one method in an assembly.
- The method to which this attribute is applied must be static and public, have no parameters, and must not return a value (or, when using async-await, return a Task).
- This method will be executed after any method annotated with the ClassCleanupAttribute or TestCleanupAttribute attribute.
ClassInitializeAttribute
This attribute can be used to identify a method that should be executed before a test of this test class is executed:
- The method must be part of a class annotated with the TestClass attribute.
- This attribute can only be applied to one method per test class.
- This method will be executed before the method annotated with the TestInitializeAttribute attribute but after the method annotated with the AssemblyInitializeAttribute attribute.
- The method to which this attribute is applied must be static and public, have a single parameter of type TestContext, and must not return a value (or, when using async-await, return a Task).
ClassCleanupAttribute
This attribute can be used to identify a method that should be executed after all tests of a test class have been executed:
- The method must be part of a class annotated with the TestClassAttribute attribute.
- This attribute can only be applied to one method per test class.
- This method will be executed after the method annotated with the TestCleanupAttribute attribute but before the method annotated with the AssemblyCleanupAttribute attribute.
- The method to which this attribute is applied must be static and public, have no parameters, and must not return a value (or, when using async-await, return a Task).
TestInitializeAttribute
This attribute can be used to identify a method that should be executed before each test method in a test class:
- The method must be part of a class annotated with the TestClassAttribute attribute.
- This attribute can only be applied to one method per test class.
- The method to which this attribute is applied must be non-static and public, have no parameters, and must not return a value (or, when using async-await, return a Task).
- This method will be executed after methods marked with the AssemblyInitialize or ClassInitialize attribute.
Instead of using the TestInitialize attribute, you could also choose to provide initialization logic in the parameterless constructor of the class, as the test executor creates a new instance of the class for each test to be executed.
TestCleanupAttribute
This attribute can be used to identify a method that should be executed after each test method in a test class:
- The method must be part of a class annotated with the TestClassAttribute attribute.
- This attribute can only be applied to one method per test class.
- The method to which this attribute is applied must be non-static and public, have no parameters, and must not return a value (or, when using async-await, return a Task).
- This method will be executed before methods marked with the ClassCleanupAttribute or AssemblyCleanupAttribute attribute.
Instead of using the TestCleanupAttribute attribute, you could let the test class implement the IDisposable interface.
Example
The example test class below makes use of all the attributes introduced above. This example also has a parameterless constructor and implements IDisposable for illustration purposes (as you would typically use either the TestInitialize and/or TestCleanup attributes or define a constructor and/or implement IDisposable).
[TestClass()] public class MyTestClass : IDisposable { public MyTestClass() { } [TestMethod()] public void MyTestMethod() { // AAA } [TestMethod()] public void MyOtherTestMethod() { // AAA } [AssemblyInitialize] public static void MyAssemblyInitialize(TestContext context) { } [AssemblyCleanup] public static void MyAssemblyCleanup() { } [ClassInitialize] public static void MyClassInitialize(TestContext context) { } [ClassCleanup] public static void MyClassCleanup() { } [TestInitialize] public void MyTestInitialize() { } [TestCleanup] public void MyTestCleanup() { } public void Dispose() { } }
The order of execution will be as follows:
- MyAssemblyInitialize
- MyClassInitialize
- MyTestClass constructor
- MyTestInitialize
- MyTestMethod
- MyTestCleanup
- Dispose
- MyTestClass constructor
- MyTestInitialize
- MyOtherTestMethod
- MyTestCleanup
- Dispose
- MyClassCleanup
- MyAssemblyCleanup
More blog posts on unit testing
BLOG
BLOG
Thanks for this well-detailed explanation Pedro