Parallel Execution with unittest
in Python
As the size of your codebase grows, developers on your team will continuously add new test cases and build new test suites. If developer changes are deployed using CI/CD, your merges will probably entail running this growing test suite every time to ensure code quality. In my previous blog post, we demonstrated how to write unit test in Python using unittest
. To ensure that this growing test suite does not waste developer time, it is necessary to learn how to run these tests in parallel.
Python unittest
does not offer a solution to this problem. In this article, I will go over two approaches to running your unittest
test cases in parallel. These two approaches are based on two python packages: threading
and multiprocessing
.
Writing Tests
We will begin by writing a class which extends unittest.TestCase
which defines the test fixture for your test cases. In this module, we will override the setUp()
and tearDown()
methods.
For this particular example, we will be defining a fixture for a selenium test case
- In the
setUp()
method, we create an instance of selenium driver for Google Chrome browser. After creating the driver instance, we navigate to Google website. - In the
tearDown()
method, we access the driver which is stored as an instance variable, and exit it using thedriver.quit()
method.
We will now write the first test case. Create a new class which extends our GoogleTestCase
. In this module, we will add the first test.
In this test case, we check if the google home page has a link with text “Gmail” which redirects us to Gmail website when it is clicked.
- For
Tauk
setup, we add the observe decorator to make Tauk aware of this test case and then register the driver instance for this test case withTauk.register_driver()
- We search for an element with “Gmail” text using the method
find_element_by_link_text
and store the element reference in thelink_with_gmail_text
variable. - We us the
assertIn()
method to verify whether the element reference’shref
attribute contains thegmail
host string.
In a similar fashion, we will create another test case called StoreTest
which checks if the google home page has a link with text “Store” which redirects us to Google Store website when it is clicked.
Executing Tests Sequentially
Let us start by creating a module called run.py
which runs the above test cases sequentially.
This module imports the test cases that we wrote, packages them into an instance of unittest.TestSuite()
and runs them with unittest.TextTestRunner()
.
There is an additional step you need to do for Tauk setup to work. You need to define the Tauk API Token and Project ID as environment variables. You can do these steps and execute the above module to run tests sequentially using the following command
NOTE: You need to get the API TOKEN and PROJECT ID from the Tauk Web UI. You can learn more about that in this article written by me.
Approach 1: Use Threads for Parallel Execution
The above module creates a class called TestThread
which extends threading.Thread
. It gets initialized with a test object which is to be run.
- The
Thread
objects are passed instances of Test methods which are imported. For example, int1
,GmailTest
class is added. - The
TestThread
has overrides the run method of the Thread object. - The
start()
method starts therun()
method on a separate child thread. - The
join()
method blocks the main thread and waits for the execution of the test to finish. - In the above scenario, we start
GmailTest
andStoreTest
at the same time and then wait for them to end.
This can be started using the same command that is shown in the previous section.
Approach 2: Use Processes for Parallel Execution
It is generally harder to stop threads with meaningful cleanup steps. Instead of having to end your unit tests abruptly, you can use processes which use a different memory space and provide a lot of abstractions when it comes to communications between the primary process and the other processes. It is often harder to debug multithreaded application as well because threads are run atomically and they can only be accessed before or after execution.
You can probably understand most of the code here as it is pretty analogous to threading. Python maintainers have chosen to design threading and multiple processes in a similar fashion.
One additional step, is that Tauk needs to be aware that tests running on separate processes are the same run. You can do so by setting the environment variable TAUK_MULTI_PROCESS
before running the tests from the command line in this manner.
Conclusion
In the above sections, we learned how to create a unit test. We learned how to integrate it with Tauk and run these tests sequentially. Next, we added parallel execution and discussed two approaches for it. Hopefully, this short guide will help you save and reduce test execution time for your growing test suite.
Lastly, if you have any questions on this blog post, you can reach out to us by joining our Discord server: