Overview [ Documentation] [ Documentation]

See also: https://github.com/microsoft/testfx/blob/main/docs/README.md

MSTest unit tests are created with dotnet new mstest -o TestProjectName.

MSTest Attributes

TestClass and TestMethod

The TestClass attribute declares a class that contains unit tests and, optionally, initialization or cleanup methods. The TestMethod attribute declares a test method. Test methods must:

  • be public void or public Task or public async Task
  • be parameterless

Unit tests projects can contain other classes that do not have the [TestClass] attribute, and test classes can contain other methods that do not have the [TestMethod] attribute. Test methods can call these other classes and methods.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Prime.Services;

namespace Prime.UnitTests.Services;

[TestClass]
public class PrimeService_IsPrimeShould
{
    private readonly PrimeService _primeService;

    public PrimeService_IsPrimeShould()
    {
        _primeService = new PrimeService();
    }

    [TestMethod]
    public void IsPrime_InputIs1_ReturnFalse()
    {
        bool result = _primeService.IsPrime(1);

        Assert.IsFalse(result, "1 should not be prime");
    }
}

DataRow

The values of the DataRow attributes are passed to the value parameter of the test method:

[TestMethod]
[DataRow(-1)]
[DataRow(0)]
[DataRow(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
    var result = _primeService.IsPrime(value);

    Assert.IsFalse(result, $"{value} should not be prime");
}

The number and types of arguments to the attribute must match the test method signature:

[TestClass]
public class TestClass
{
    [TestMethod]
    // Setting the DisplayName property modifies the display name in Visual Studio and in loggers:
    [DataRow(1, "message", true, 2.0), DisplayName="Functional Case FC01"]
    public void TestMethod1(int i, string s, bool b, float f) {}
    
    [TestMethod]
    [DataRow(new string[] { "line1", "line2" })]
    public void TestMethod2(string[] lines) {}

    [TestMethod]
    [DataRow(null)]
    public void TestMethod3(object o) {}

    [TestMethod]
    [DataRow(new string[] { "line1", "line2" }, new string[] { "line1.", "line2." })]
    public void TestMethod4(string[] input, string[] expectedOutput) {}
}

Also, params can be used to capture multiple inputs of DataRow:

[TestMethod]
[DataRow(1, 2, 3, 4)]
public void TestMethod(params int[] values) {}

Attributes for Initialization and Cleanup

Unless otherwise noted, all methods marked with these attributes:

  • Must be static void or static Task or static async Task
  • Can appear only once
  • Must be in a TestClass
AttributeWhen is method calledParametersComments
[AssemblyInitialize]Right after assembly is loadedTestContextN/A
[AssemblyCleanup]Right before assembly is unloadN/AN/A
[ClassInitialize]Right before the class is loaded but after the static constructorTestContextN/A
[ClassCleanup]Right after the class is unloadedN/AN/A
[TestInitialize]Right before the test is startedN/AMore suitable for long or async initializations than the class initializer.
Always called after the class constructor and always called for each test, including each data row of data-driven tests.
May appear more than once.
[TestCleanup]Right after the test is finishedN/AMore suitable for long or async cleanups than the class cleanup.
Always called just before the Dispose{Async} and always called for each test, including each data row of data-driven tests.
May appear more than once.
[TestClass]
public class MyTestClass
{
    [AssemblyInitialize]
    public static void AssemblyInitialize(TestContext testContext) { }

    [AssemblyCleanup]
    public static void AssemblyCleanup() { }

    [ClassInitialize]
    public static async Task ClassInitialize(TestContext testContext) { }

    [ClassCleanup]
    public static async Task ClassCleanup() { }

    [TestInitialize]
    public async Task TestInitialize() { }

    [TestCleanup]
    public async Task TestCleanup() { }
}

TestContext Class

These attributes appear in the Visual Studios Properties window of a particular test method. They are not meant to be accessed through the code of a unit test. They are used to provide metadata for the test:

  • OwnerAttribute
  • DescriptionAttribute
  • IgnoreAttribute
  • PriorityAttribute
  • TestPropertyAttribute
  • WorkItemAttribute

DeploymentItemAttribute

For deployment items, without a custom output path, the copied files will be in the TestResults folder inside the project folder. [DeploymentItem] copies files or folders specified as deployment items to the deployment directory. It can be used on [TestClass]’s or [TestMethod]’s:

[TestClass] 
[DeploymentItem(@"C:\classLevelDepItem.xml")]   // Copy file using some absolute path
public class UnitTest1
{
    [TestMethod]
    [DeploymentItem(@"..\..\methodLevelDepItem1.xml")]   // Copy file using a relative path from the dll output location
    [DeploymentItem(@"C:\DataFiles\methodLevelDepItem2.xml", "SampleDataFiles")]   // File will be added under a SampleDataFiles in the deployment directory
    public void TestMethod1()
    {
        string textFromFile = File.ReadAllText("classLevelDepItem.xml");
    }
}

PrivateObject and PrivateType

When generating a unit test for a private method, a private accessor class is generated, which instantiates a PrivateObject. This is a wrapper class that uses reflection as part of the private accessor process.

PrivateType is used for calling private static methods (instead of private instance methods).

More information.

Unit Test Timeouts

MSTest unit tests can be configured with a timeout:

[TestMethod]
[Timeout(2000)]  // Milliseconds
// Or, for the maximum allowed time:
[Timeout(TestTimeout.Infinite)]
public void My_Test() { /*...*/ }

Assert Classes [ Documentation]

Microsoft.VisualStudio.TestTools.UnitTesting contains Assert classes to verify specific functionality. A unit test only reports correctness of the code’s behavior if Assert statements are included.

ClassUse
CollectionAssertCompare collections of objects
Verify the state of a collection
StringAssertCompare and examine strings
ie: Contains, Matches, StartsWith
AssertFailedExceptionThrown whenever a test fails.
A failure is a test timeout, unexpected exception, or an assert statement that produces a Failed result
AssertInconclusiveExceptionThrown whenever a test produces a result of Inconclusive.
Added to tests not yet ready to be run (still being developed).
Assert.ThrowExceptionAsserts that an exception you expect to be thrown by a method is actually thrown