Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Use the Assert classes of the Microsoft.VisualStudio.TestTools.UnitTesting namespace to verify specific functionality. A test method exercises the code in your application but reports correctness only when you include Assert statements.
Overview
MSTest provides three assertion classes:
| Class | Purpose |
|---|---|
Assert |
General-purpose assertions for values, types, and exceptions. |
StringAssert |
String-specific assertions for patterns, substrings, and comparisons. |
CollectionAssert |
Collection assertions for comparing and validating collections. |
Important
For new code, always use the Assert class. The StringAssert and CollectionAssert classes are likely to be deprecated in a future release. They're maintained primarily for backward compatibility, but they're not recommended because splitting assertions across three types hurts discoverability.
All assertion methods accept an optional message parameter that displays when the assertion fails, helping you identify the cause:
Assert.AreEqual(expected, actual, "Values should match after processing");
The Assert class
Use the Assert class to verify that the code under test behaves as expected.
Common assertion methods
[TestMethod]
public async Task AssertExamples()
{
// Equality
Assert.AreEqual(5, calculator.Add(2, 3));
Assert.AreNotEqual(0, result);
// Reference equality
Assert.AreSame(expected, actual);
Assert.AreNotSame(obj1, obj2);
// Boolean conditions
Assert.IsTrue(result > 0);
Assert.IsFalse(string.IsNullOrEmpty(name));
// Null checks
Assert.IsNull(optionalValue);
Assert.IsNotNull(requiredValue);
// Type checks
Assert.IsInstanceOfType<IDisposable>(obj);
Assert.IsNotInstanceOfType<string>(obj);
// Exception testing (MSTest v3.8+)
Assert.ThrowsExactly<ArgumentNullException>(() => service.Process(null!));
await Assert.ThrowsExactlyAsync<InvalidOperationException>(
async () => await service.ProcessAsync());
}
Available APIs
- Assert.AreEqual
- Assert.AreNotEqual
- Assert.AreNotSame
- Assert.AreSame
- Assert.Contains
- Assert.ContainsSingle
- Assert.DoesNotContain
- Assert.DoesNotEndWith
- Assert.DoesNotMatchRegex
- Assert.DoesNotStartWith
- Assert.Fail
- Assert.HasCount
- Assert.Inconclusive
- Assert.IsEmpty
- Assert.IsFalse
- Assert.IsGreaterThan
- Assert.IsGreaterThanOrEqualTo
- Assert.IsInRange
- Assert.IsInstanceOfType
- Assert.IsLessThan
- Assert.IsLessThanOrEqualTo
- Assert.IsNegative
- Assert.IsNotEmpty
- Assert.IsNotInstanceOfType
- Assert.IsNotNull
- Assert.IsNull
- Assert.IsPositive
- Assert.IsTrue
- Assert.MatchesRegex
- Assert.StartsWith
- Assert.Throws
- Assert.ThrowsAsync
- Assert.ThrowsExactly
- Assert.ThrowsExactlyAsync
New collection and equivalence assertions in MSTest 4.3
Note
The following assertion methods were introduced in MSTest 4.3.0.
Assert.AreSequenceEqual/Assert.AreNotSequenceEqual— element-wise sequence comparison. PassSequenceOrder.InAnyOrderto ignore element order.Assert.AreEquivalent/Assert.AreNotEquivalent— deep structural comparison of two objects or collections.Assert.ContainsAll/Assert.DoesNotContainAll— assert that a collection contains (or doesn't contain) every expected element.Assert.AreAllNotNull— assert that every element of a collection is non-null.Assert.AreAllDistinct— assert that all elements of a collection are distinct.Assert.AreAllOfType— assert that every element of a collection is of an expected type.
When comparing collections, prefer these methods over Assert.AreEqual, which compares references rather than elements.
MSTest 4.3 also adds:
Assert.AddValueFormatterto customize how values are rendered in assertion failure messages.- Span<T> and Memory<T> overloads for
Assert.HasCount. - Structured assertion failure messages for
Assert.IsTrue,Assert.IsFalse,Assert.IsNull, andAssert.IsNotNullthat include the evaluated expression. - Interpolated-string message overloads for the async
Assert.ThrowsAsync/Assert.ThrowsExactlyAsyncmethods, and rejection ofValueTask<TResult>-returning delegates that would otherwise not be awaited.
Soft assertions with Assert.Scope()
Important
Assert.Scope() is an experimental API. Using it produces the MSTESTEXP diagnostic, which you suppress (for example, with #pragma warning disable MSTESTEXP or in your project's .editorconfig file) to acknowledge that the shape and behavior of the API can change in future releases.
By default, every assertion throws an AssertFailedException as soon as it fails, which ends the test immediately. Assert.Scope() introduces soft assertions: while a scope is active, assertion failures are collected instead of thrown, so execution continues and you can see every failure in the scope at once. When the scope is disposed, the collected failures are reported together:
[TestMethod]
public void ValidatePerson()
{
using (Assert.Scope())
{
Assert.AreEqual("Jane", person.FirstName); // failure collected, execution continues
Assert.AreEqual("Doe", person.LastName); // failure collected, execution continues
Assert.IsTrue(person.IsActive); // failure collected, execution continues
}
// On Dispose, all collected failures are reported together.
}
When the scope is disposed:
- If exactly one failure was collected, the original
AssertFailedExceptionis thrown. - If multiple failures were collected, a single
AssertFailedExceptionis thrown that wraps all of them in anAggregateException.
Postconditions aren't enforced inside a scope
Because a failing assertion no longer throws inside a scope, code that runs after it can't rely on the assertion having succeeded. This applies to every postcondition, including nullability and type narrowing:
using (Assert.Scope())
{
Assert.IsNotNull(item);
// 'item' might still be null here: the failure was collected, not thrown.
Assert.AreEqual("expected", item.Value);
// 'item.Value' might not equal "expected" either.
}
If a failed assertion would lead to a NullReferenceException (or any other exception) on a later line within the scope, that secondary exception is a symptom of the already-collected failure, not a separate bug. The original assertion failure is still reported when the scope is disposed.
Value-returning assertions return null/default on failure inside a scope
Some assertions return a value on success—for example, Throws and ThrowsExactly return the caught exception, and ContainsSingle returns the matched element. When one of these assertions fails inside a scope, the failure is collected and the method returns null/default instead of throwing:
using (Assert.Scope())
{
// No exception is thrown by the lambda, so the assertion fails. The failure is
// collected and 'ex' is null. Accessing 'ex' below throws NullReferenceException.
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(() => { });
_ = ex.Message; // NullReferenceException—don't use the return value in a scope
}
Don't rely on the value returned by a soft assertion inside a scope. If you need the returned value (such as the caught exception), call the assertion outside the scope, or restructure the test so nothing depends on the return value until after the scope is disposed.
Assert.Fail and Assert.Inconclusive always throw
Fail and Inconclusive are never soft. They always throw immediately, even inside a scope, because they express an unconditional test outcome. Use one of them when a condition is critical and the rest of the test can't meaningfully continue without it.
Nested scopes aren't supported
You can't nest Assert.Scope() calls. Only one assertion scope can be active at a time.
The StringAssert class
Use the StringAssert class to compare and examine strings.
Warning
The StringAssert class is likely to be deprecated in a future release. It's maintained for backward compatibility only and isn't recommended for new code. All StringAssert methods have equivalents on the Assert class, which offers better discoverability. To migrate existing usages, see analyzer MSTEST0046.
Available APIs are:
- StringAssert.Contains
- StringAssert.DoesNotMatch
- StringAssert.EndsWith
- StringAssert.Matches
- StringAssert.StartsWith
The CollectionAssert class
Use the CollectionAssert class to compare collections of objects, or to verify the state of a collection.
Warning
The CollectionAssert class is likely to be deprecated in a future release. It's maintained primarily for backward compatibility and isn't recommended for new code. When an equivalent method exists on Assert (such as Assert.Contains, Assert.DoesNotContain, or Assert.HasCount), use Assert for better discoverability.
Available APIs are:
- CollectionAssert.AllItemsAreInstancesOfType
- CollectionAssert.AllItemsAreNotNull
- CollectionAssert.AllItemsAreUnique
- CollectionAssert.AreEqual
- CollectionAssert.AreEquivalent
- CollectionAssert.AreNotEqual
- CollectionAssert.AreNotEquivalent
- CollectionAssert.Contains
- CollectionAssert.DoesNotContain
- CollectionAssert.IsNotSubsetOf
- CollectionAssert.IsSubsetOf
Create custom assertions with Assert.That
The built-in assertion methods don't cover every scenario. To extend the assertion infrastructure with your own checks, MSTest exposes the Assert.That singleton property as an extensibility hook. You add custom assertions as C# extension methods on the Assert instance type, and callers invoke them with the familiar Assert.That.MyAssertion(...) syntax.
For better discoverability, organize project-wide assertions in a dedicated static class. Custom assertions reached through Assert.That show up alongside the built-in methods in IntelliSense, so consumers don't have to remember a separate helper type.
Author a custom assertion
Add an extension method that targets the Assert type and throws AssertFailedException when the condition fails:
using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
public static class CustomAssertExtensions
{
public static void IsPrime(this Assert assert, int value)
{
if (value < 2 || Enumerable.Range(2, (int)Math.Sqrt(value) - 1).Any(i => value % i == 0))
{
throw new AssertFailedException($"Assert.That.IsPrime failed. Value <{value}> is not a prime number.");
}
}
}
Use a custom assertion
After you import the namespace that contains your extension methods, call your custom assertion through Assert.That:
[TestMethod]
public void Compute_ReturnsPrime()
{
int result = _calculator.NextPrime(10);
Assert.That.IsPrime(result);
}
Extension hooks on StringAssert and CollectionAssert
The StringAssert.That and CollectionAssert.That properties expose the same singleton pattern for backward compatibility. For new custom assertions, always target Assert.That. Otherwise, your helpers inherit the same discoverability problems as the legacy classes, and they'll need migration if StringAssert and CollectionAssert are deprecated.
Assert.That property versus Assert.That(...) method
Note
Don't confuse the Assert.That singleton property—used as an extensibility hook—with the Assert.That(() => condition) method added in MSTest 3.8. The latter accepts a Boolean expression and produces detailed failure messages by analyzing the expression tree (for example, Assert.That(() => order.Total > 0)). The two APIs share a name but serve different purposes.
Best practices
Use specific assertions: Prefer
AreEqualoverIsTrue(a == b)for better failure messages.Include descriptive messages: Help identify failures quickly with clear assertion messages.
Test one thing at a time: Each test method should verify a single behavior.
Use
Throws/ThrowsExactlyfor exceptions: In MSTest v3.8+, preferAssert.Throws,Assert.ThrowsExactly, and their async counterparts (ThrowsAsync,ThrowsExactlyAsync) over theExpectedExceptionattribute.Prefer
AssertoverStringAssert/CollectionAssert: For better discoverability and consistency, use theAssertclass. TheStringAssertandCollectionAssertclasses are likely to be deprecated in a future release.Extend
Assert.Thatfor custom assertions: For consistent discoverability, add custom assertions as extension methods onAssertand invoke them throughAssert.That. Don't targetStringAssert.ThatorCollectionAssert.Thatin new code.
Related analyzers
The following analyzers help ensure proper usage of assertions:
- MSTEST0006 - Avoid
ExpectedExceptionattribute, useAssert.Throwsmethods instead. - MSTEST0017 - Assertion arguments should be passed in the correct order.
- MSTEST0023 - Do not negate boolean assertions.
- MSTEST0025 - Prefer
Assert.Failover always-false conditions. - MSTEST0026 - Assertion arguments should avoid conditional access.
- MSTEST0032 - Review always-true assert conditions.
- MSTEST0037 - Use proper assert methods.
- MSTEST0038 - Avoid
Assert.AreSamewith value types. - MSTEST0039 - Use newer
Assert.Throwsmethods. - MSTEST0040 - Avoid using asserts in async void context.
- MSTEST0046 - Use
Assertinstead ofStringAssert. - MSTEST0051 -
Assert.Throwsshould contain a single statement. - MSTEST0053 - Avoid
Assertformat parameters. - MSTEST0058 - Avoid asserts in catch blocks.