Writing unit tests is no developer’s favorite part of coding. Tests tend to be poorly written and maintained, and keeping them up to date takes time away from writing the features they should be testing. Fortunately, the Arrange/Act/Assert pattern (also called Given/When/Then) is a simple but valuable pattern that defines the order of operations for tests.
Each individual unit test a developer writes will have a step for Arrange, Act, and Assert. I like to include comments at the beginning of each section for added clarity. By implementing this pattern, new developers can look at a unit test and immediately know what’s happening. As an example, I’ll detail how to test that a user’s email address is valid.
The Arrange step sets up the unit tests. It’s where a developer sets up variables and settings, mock databases, and methods using their favorite framework. The unit test is decluttered and easier to read and maintain by setting up everything in one code block.
For the email address example, create a new user and set their email address.
var User = new User();
User.EmailAddress = “email@example.com”;
The Act step performs the action that needs to be tested. In most of my test cases, this entails calling a single method. The single call may rely on variables or mocked services and methods, but that should be set up in the Arrange step. By following this pattern, the action of the unit test will remain focused on the target behavior, leaving no room to call other methods or test another behavior.
In the example, call a method that verifies the user’s email address and retrieves the returned value.
var Result = User.VerifyEmailAddress();
The previous Act step should produce a result. The Assert step verifies that the result is what it’s expected to be. In this example, call an Assert statement on the Result variable using FluentAssertions.
This strict structure forces independent actions. The Assert must come last without any additional setup along the way or after the assertion. It may be tempting as a developer to test several situations for a method in a single unit test. To follow our example, after the Result value is tested, a developer could continue to change the email address to test negative scenarios. Doing that could lead to incorrect test results or unintended side effects from the code. It would also make debugging the code more complex. If the user instead created a test for each scenario (or made multiple users with descriptive names in the Arrange step), only one action would be tested per user, and a failed test would give a more obvious result.
The Arrange/Act/Assert pattern is an intuitive way to speed up unit test coding. It keeps tests organized, quick to write, easy to read, and independent. I recommend implementing it for any new solution or refactoring current unit tests.