Making Better Unit Tests: AAA Pattern

unittest

What is Unit Testing?

Unit testing is one of the software testing types which includes the initial testing phase where the smallest components or the modules of a software are tested individually. With this method of testing, both testers and developers can isolate each module, identify and fix the system defects at a very early stage of the software development lifecycle (SDLC). Primarily, a unit test verifies different behavioral aspects of the system under test and can be broadly classified into state-based and interaction-based unit testing.
A typical unit test consists of three phases which include the first initialization phase where it initializes a small piece of an application it wants to test. The second phase is the addition phase where it adds a stimulus to the system under test and finally, the third phase is the result phase where it observes the resulting application behavior. Evidently, if the observed behavior is consistent with expectations, then the unit test passes else it fails. This indicates there is a problem somewhere in the system under test. These three test phases are named as Arrange, Act and Assert or commonly known as AAA.

Arrange Act Assert

The 3A pattern is simple and provides a uniform structure for all tests in the suite. This uniform structure is one of its biggest advantages: once you get used to this pattern, you can read and understand the tests more easily. That, in turn, reduces the maintenance cost for your entire test suite.

AAA structured test case walk through

This is the simple pattern in the structure of every unit test. The following is a Calculator class with a single method which calculates a sum of two numbers. The Calculator class will then be imported in the unit test and will be used to test the addition of two numbers using AAA pattern.

add class


The below Listing shows how we can test the above calculator class implementation using the arrange, act and assert structure. This structure keeps the code clean and easy to read. This test may seem easy and trivial, but we can use it to illustrate our pattern. We can see the comments denoting each of the AAA patterns.
Arrange-Act-Assert is powerful because it is simple. It forces tests to focus on independent, individual behaviors. It separates setup actions from the main actions. It requires test to make verifications and not merely run through motions.

AAA test

Behavior-Driven Development follows the Arrange-Act-Assert pattern.

  1. The Arrange step assigns values to “value_a” and “value_b” variable.
  2. The Act step calls the “add_number” function using the “value_a” and “value_b” variable and stores the returned value in a variable named “addition”.
  3. The Assert step verifies that “addition” is the sum of “value_a” and “value_b”.

The natural inclination is to start writing the test with the Arrange section. After all, it comes before the other two. And this approach works well in the vast majority of cases. But starting with the Assert section is a viable option too. If you practice Test-Driven Development, i.e. when you write a test before the production code, you don’t necessarily know enough about a given feature’s behavior, which can lead to the creation of a faulty test. It is advantageous to first outline what you expect from the behavior and then figure out how to develop the system to meet this expectation. The Code used for the demonstration of the above unit test can be found here

External Data for Testing

For the purpose of unit testing, aside from the AAA pattern, the other important factor is test data. data for testing is a crucial requirement that needs to be fulfilled for a successful Software Development Cycle. Working with a data set in product development often requires changes such as editing, moving, adding or deleting data. Because of this, running tests on hard-coded data each time can become challenging. Testers have to create multiple test scripts or modify existing tests multiple times and run them individually. Such tasks can easily become boring and cumbersome, also affecting the pace of development.
Demonstrating on the above referenced Calculator class, below is the sample external data in the form of a .CSV file.

data

The above file is a comma seperated (.csv) file, which is the most common type of file used in testing. A .csv file can be read using pandas in python. pd.read_csv is the command used to read from a .csv file to a dataframe. The values in the dataframe can then be used to perform testing operations. As we can see below, we have created a function to read any .csv file.

data

Here we have imported the packages os and pandas, os package helps in defining the path where the file is present, whereas we can use the pandas package to read the .csv file. We can now use this read_from_file function to read any .csv file and use it for our unit test cases. Further we can always add or delete values from the files without touching the code.
Below we have the AAA pattern test case using external data.

data

In the above example, we again perform the Arrange, Act, Assert pattern testing, but this time, we use external data for the same. The value_a, value_b and addition_result are specified using the index of the dataframe. The whole function can be looped to test all the rows of the dataframe. The source code for the above demonstration using external data for testing can be found here.


The complete code can be accessed on Calculator Github