How to create test data with Object Mothers
Tags: beginners, csharp, testing
Published: 2021-07-05 15:29:19

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

One single tip to [write better tests](https://canro91.github.io/2020/11/02/UnitTestingTips/) is to reduce noise inside our tests. For this, we can use builder methods. They help us to simplify complex Arrange parts or setup scenarios of our tests.

This time, let's use Object Mothers to reduce noise inside our unit tests when creating test data.

## Without Object Mothers

Let's validate credit cards. We will use the [FluentValidation](https://fluentvalidation.net/) library to create a validator class. We want to check if a credit card is expired or not. We can write tests like these ones.

```csharp
using FluentValidation.TestHelper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace UsingObjectMothers
{
    [TestClass]
    public class CreditCardValidationTests
    {
        [TestMethod]
        public void CreditCard_ExpiredYear_ReturnsInvalid()
        {
            var validator = new CreditCardValidator();

            var creditCard = new CreditCard
            {
                CardNumber = "4242424242424242",
                ExpirationYear = DateTime.Now.AddYears(-1).Year,
                ExpirationMonth = DateTime.Now.Month,
                Cvv = 123
            };
            var result = validator.TestValidate(creditCard);

            result.ShouldHaveAnyValidationError();
        }

        [TestMethod]
        public void CreditCard_ExpiredMonth_ReturnsInvalid()
        {
            var validator = new CreditCardValidator();

            var creditCard = new CreditCard
            {
                CardNumber = "4242424242424242",
                ExpirationYear = DateTime.Now.Year,
                ExpirationMonth = DateTime.Now.AddMonths(-1).Month,
                Cvv = 123
            };
            var result = validator.TestValidate(creditCard);

            result.ShouldHaveAnyValidationError();
        }
    }
}
```

In these tests, we used the `TestValidate()` and `ShouldHaveAnyValidationError()` methods from FluentValidation to write better assertions.

In each test, we created a `CreditCard` object and modified one single property for the given scenario. We had duplication and magic values when initializing the `CreditCard` object.

## Object Mothers

In our tests, we should give enough details to our readers, but not too many details to make our tests noisy. We should keep the details at the right level.

In our previous tests, we only cared for the expiration year and month in each test. We can abstract the creation of the `CreditCard` objects to avoid repetition.

One alternative to abstract the creation of `CreditCard` objects is to use an object mother.

**An object mother is a factory method or property holding a ready-to-use input object. Inside each test, the properties of this object are updated to match the scenario under test.**

For our example, we can create a `CreditCard` property with valid defaults and tweak it inside each test.

Our tests with an object mother for credit cards will look like this.

```csharp
[TestClass]
public class CreditCardValidationTests
{
    [TestMethod]
    public void CreditCard_ExpiredYear_ReturnsInvalid()
    {
        var validator = new CreditCardValidator();

        // Instead of creating a new card object each time,
        // we rely on this new CreditCard property
        var request = CreditCard;
        request.ExpirationYear = DateTime.Now.AddYears(-1).Year;
        var result = validator.TestValidate(request);

        result.ShouldHaveAnyValidationError();
    }

    [TestMethod]
    public void CreditCard_ExpiredMonth_ReturnsInvalid()
    {
        var validator = new CreditCardValidator();

        var request = CreditCard;
        request.ExpirationMonth = DateTime.Now.AddMonths(-1).Month;
        var result = validator.TestValidate(request);

        result.ShouldHaveAnyValidationError();
    }

    // We have this new property to hold a valid credit card
    private CreditCard CreditCard
        => new CreditCard
        {
            CardNumber = "4242424242424242",
            ExpirationYear = DateTime.Now.Year,
            ExpirationMonth = DateTime.Now.Month,
            Cvv = 123
        };
}
```

Notice the `CreditCard` property in our test class and how we update its values from test to test.

Voilà! That's how we can use object mothers to create test data and simplify our tests. Simple trick, right?

Object mothers are fine if you don't have lots of variations of the object being constructed. But, if you do, use builders. To learn about builders, check my post about [the Builder pattern](https://canro91.github.io/2021/04/26/CreateTestValuesWithBuilders/).

Remember, in your tests you should give enough details to your readers, but not too many to make your tests noisy. Don't bore your test readers, but don't surprise them either.

_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!_