- Can we use unit testing best practices in end2end (black box) tests?
- How to structure an automated test?
- How to improve readability and maintainability of automated tests?
If you have the above questions in mind, this post is for you. I would like to share few guidelines/practices I follow while creating a new automated test:
AAA pattern
As par this pattern we can split an automated test into 3 distinct parts – Arrange, Act
and Assert.
o In the arrange section, we perform the needed dependencies for the test to start.
o In the act section, we call the method under test from SUT, perform needed actions and capture the output value required.
o In the assert section, we verify the outcome of the test.
The arrange section of a test is the largest. When the test requires a lot of setup before starting, we can either use a private method or delegate that to a factory class.
In an Act section, multiple actions can be performed based on the requirement we are testing.
Finally, a test should verify single behaviour at a time in the assert section. Key thing to watch here is what behaviour we are verifying and take a call based on that like how many assertions are actually needed to validate that. If test is checking multiple behaviour, it’s a good idea to split it into multiple tests accordingly which will make each test atomic.
Note: AAP pattern is not providing any guidance on teardown part of a test. We use separate method to teardown a test, which is not part of AAA but a must have thing for an automated test.
Example of AAA pattern:
//---Arrange
//Example: Open a the search page we are testing
//Initialize the page objects needed
//Initialize the other dependencies needed for example the expected result for this //test
//---Act
//Example: Search for an item and capture the result
//---Assert
//Example: Validate the expected outcome with the actual outcome.
Avoid if branching/looping in test
When a test contains conditional or branching statements, it verifies too many things at once, making it difficult to read and comprehend.
Reusing code between tests
It’s also important to know how and when to reuse code between tests. A good way to shorten and simplify tests is to reuse code between arrange sections. In cases where there are multiple tests in a single class that use the same arrange section, it is good to move that code to a reusable method. Do not add arrange code in constructor which is an anti-pattern that creates high coupling between the tests. By reading a test with this pattern, we may not be able to understand exactly what it is trying to accomplish. We can use inheritance if all the tests needs some common arrangement for example connect to a database.
Naming convention to be used for a test
Test names should be expressive. It is important to name your tests appropriately so that you understand what they verify and how they interact with the underlying system.
Fluent Assertions
The readability of the tests can be further improved by using fluent assertion libraries