How to write better assertions: 5 Best Practices
Tags: csharp, testing, beginners, tutorial
Published: 2021-08-02 13:50:01

_I originally posted this post [on my blog](https://canro91.github.io/2021/07/19/WriteBetterAssertions/) a couple of weeks ago. It's part of a series I've been publishing, called [Unit Testing 101](https://canro91.github.io/UnitTesting)_

There's a lot to say about writing good unit tests. This time, let's focus on Assertions. Here you have 5 tips to write better assertions on your tests.

> TL;DR
> 1. Follow the Arrange/Act/Assert (AAA) pattern
> 2. Separate each A of the AAA pattern
> 3. Don't put logic in your assertions
> 4. Have a single Act and Assert
> 5. Use the right Assertion methods

## 1. Follow the Arrange/Act/Assert (AAA) pattern

If you could take home only one thing: **follow the Arrange/Act/Assert (AAA) pattern**.

The Arrange/Act/Assert (AAA) pattern states that each test should contain three parts: Arrange, Act and Assert.

In the Arrange part, we create input values and initialize classes to call the entry point of the code under test.

In the Act part, we call the entry point to trigger the logic being tested.

In the Assert part, we verify the expected behavior of the code under test.

For example, let's bring back one test for [Stringie](https://github.com/canro91/Testing101), a (fictional) library to manipulate strings, to show the AAA pattern. Notice how each test has these 3 parts.

```csharp
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Stringie.UnitTests
{
    [TestClass]
    public class RemoveTests
    {
        [TestMethod]
        public void Remove_ASubstring_RemovesThatSubstring()
        {
            // Arrange
            string str = "Hello, world!";

            // Act
            string transformed = str.Remove("Hello");

            // Assert
            Assert.AreEqual(", world!", transformed);
        }

        [TestMethod]
        public void Remove_NoParameters_ReturnsEmpty()
        {
            // Arrange
            string str = "Hello, world!";

            // Arrange
            string transformed = str.Remove();

            // Arrange
            Assert.AreEqual(0, transformed.Length);
        }
    }
}
```
For the sake of the example, we have put comments in each part. You don't need to do that on your own tests.

ICYMI, we've been using Stringie to [write our first unit tests in C#](https://canro91.github.io/2021/03/15/UnitTesting101/) and to learn about [four common mistakes when writing tests](https://canro91.github.io/2021/03/29/UnitTestingCommonMistakes/).

## 2. Separate each A of the AAA pattern

**Use line breaks to visually separate the AAA parts of each test.**

Take a look at the previous tests without line breaks between each AAA part.

```csharp
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Stringie.UnitTests
{
    [TestClass]
    public class RemoveTests
    {
        [TestMethod]
        public void Remove_ASubstring_RemovesThatSubstring()
        {
            string str = "Hello, world!";
            string transformed = str.Remove("Hello");
            Assert.AreEqual(", world!", transformed);
        }

        [TestMethod]
        public void Remove_NoParameters_ReturnsEmpty()
        {
            string str = "Hello, world!";
            string transformed = str.Remove();
            Assert.AreEqual(0, transformed.Length);
        }
    }
}
```

Not that bad. The larger the tests, the harder it gets. Have the three AAA parts separated to make your tests easier to read.

In case you're wondering about those weird method names, that's one of [four test naming conventions](https://canro91.github.io/2021/04/12/UnitTestNamingConventions/) I've found.

## 3. Don't put logic in your assertions

**Don't repeat the logic under test in your assertions.** And, please, don't copy the tested logic and paste it into private methods in your test files to use it in your assertions.

Use known or pre-calculated values. Declare constants for common expected values.

```csharp
[TestMethod]
public void Remove_ASubstring_RemovesThatSubstringFromTheEnd()
{
    string str = "Hello, world! Again, Hello";

    string transformed = str.Remove("Hello").From(The.End);

    // Notice how we hardcode an expected value here
    Assert.AreEqual("Hello, world! Again,", transformed);
}
```

Notice how we hardcoded the expected value on our previous tests.

## 4. Have a single Act and Assert

**Have a single Act and Assert parts in your tests**. Use parameterized tests to test the same scenario with different test values. And, don't put the test values inside an array to loop through it to assert on each value.

This is a parameterized test with MSTest.

```csharp
[DataTestMethod]
[DataRow("Hello")]
[DataRow("HELLO")]
[DataRow("HeLlo")]
public void Remove_SubstringWithDifferentCase_RemovesSubstring(string substringToRemove)
{
    var str = "Hello, world!";

    var transformed = str.RemoveAll(substringToRemove).IgnoringCase();

    Assert.AreEqual(", world!", transformed);
}
```

## 5. Use the right Assertion methods

**Use the right assertion methods of your testing framework**. And, don't roll your own assertion framework.

For example, prefer `Assert.IsNull(result);` over `Assert.AreEqual(null, result);`. And, prefer `Assert.IsTrue(result)` over `Assert.AreEqual(true, result);`.

When working with strings, prefer methods from `StringAssert` class like `Contains()` and `StartsWith()` instead of comparing exactly two strings.

Voilà! These are 5 tips to write better assertions. If you want a more complete list of best practices to write your unit tests, check my post [Unit Testing Best Practices](https://canro91.github.io/2021/07/05/UnitTestingBestPractices/).

_Upgrade your unit testing skills with my course: [Mastering C# Unit Testing with Real-world Examples](https://www.udemy.com/course/mastering-csharp-unit-testing-with-real-world-examples/?referralCode=8456B1B78E2EDE923174) on Udemy. Practice with hands-on exercises and learn best practices by refactoring real-world unit tests._

_Happy testing!_