DEV Community

Eric Elsholz
Eric Elsholz

Posted on • Edited on

Arrange, Adjust, Act, Assert (4A) pattern for writing unit tests

The Arrange, Act, Assert (AAA) pattern is a common pattern for writing unit tests. In this pattern, each unit test has three sections, in this order:

Arrange Set up the test
Act Do the thing being tested
Assert Confirm that everything turned out the way you expected

An example of AAA in C#:

[TestMethod]
public void UserManager_CreateUser_ReturnsErrorCode_WhenEmailIsNotProvided()
{
    #region Arrange
    UserManager classUnderTest = new UserManager();
    UserDetails userDetails = new UserDetails
    {
        UserName = "foouser",
        Email = null,
        FirstName = "Foo",
        LastName = "Doe"        
    };
    #endregion

    #region Act
    CreateUserResult result = classUnderTest.CreateUser(userDetails);
    #endregion

    #region Assert
    Assert.AreEqual(19, result.ErrorCode);
    Assert.IsNull(result.User);
    #endregion
}
Enter fullscreen mode Exit fullscreen mode

The Arrange, Adjust, Act, Assert (4A) pattern adds an Adjust section, and changes the Arrange section slightly.

Arrange Set up the test, but use the exact same code as what you are using in the Arrange section of all of the other tests which test the same class/method/function
Adjust Make the adjustment that is special to this one test
Act Do the thing being tested
Assert Confirm that everything turned out the way you expected

Every test has the exact same Arrange section, but each test has its own unique Adjust section which describes the scenario being tested.

An example of 4A in C#:

[TestMethod]
public void UserManager_CreateUser_CreatesANewUser()
{
    #region Arrange
    UserManager classUnderTest = new UserManager();
    UserDetails userDetails = new UserDetails
    {
        UserName = "foouser",
        Email = "foo@example.com",
        FirstName = "Foo",
        LastName = "Doe"        
    };
    #endregion

    #region Adjust
    // The base or "happy path" scenario does not have any adjustment
    #endregion

    #region Act
    CreateUserResult result = classUnderTest.CreateUser(userDetails);
    #endregion

    #region Assert
    Assert.AreEqual(0, result.ErrorCode);
    Assert.IsNotNull(result.User);
    #endregion
}

[TestMethod]
public void UserManager_CreateUser_ReturnsErrorCode_WhenUserNameIsNotProvided()
{
    #region Arrange
    UserManager classUnderTest = new UserManager();
    UserDetails userDetails = new UserDetails
    {
        UserName = "foouser",
        Email = "foo@example.com",
        FirstName = "Foo",
        LastName = "Doe"        
    };
    #endregion

    #region Adjust
    userDetails.UserName = null;
    #endregion

    #region Act
    CreateUserResult result = classUnderTest.CreateUser(userDetails);
    #endregion

    #region Assert
    Assert.AreEqual(17, result.ErrorCode);
    Assert.IsNull(result.User);
    #endregion
}

[TestMethod]
public void UserManager_CreateUser_ReturnsErrorCode_WhenEmailIsNotProvided()
{
    #region Arrange
    UserManager classUnderTest = new UserManager();
    UserDetails userDetails = new UserDetails
    {
        UserName = "foouser",
        Email = "foo@example.com",
        FirstName = "Foo",
        LastName = "Doe"        
    };
    #endregion

    #region Adjust
    userDetails.Email = null;
    #endregion

    #region Act
    CreateUserResult result = classUnderTest.CreateUser(userDetails);
    #endregion

    #region Assert
    Assert.AreEqual(19, result.ErrorCode);
    Assert.IsNull(result.User);
    #endregion
}
Enter fullscreen mode Exit fullscreen mode

Why use 4A? You will write tests faster and those tests will be more readable and maintainable.

The Arrange sections are identical across tests, so if you understand the setup for one test, you understand it for all.

The identical Arrange sections also make test maintenance easier. When you need to change your test setup as a result of a class change, you can update all of your Arranges with a single find/replace.

The Adjust section is the minimum amount of code needed to describe how a test is different, making it much easier to understand the scenario being tested.

Writing a new test is a simple copy/paste from any of the existing tests. You change the Adjust section to describe the new scenario, and you change the Assert section if the expected behavior is different. Everything else (the Arrange and Act sections) can stay the same.

Take 4A for a spin and see what you think!

Top comments (0)