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.
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.
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.
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.
Behavior-Driven Development follows the Arrange-Act-Assert pattern.
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
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.
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.
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.
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.