Getting Started with PyTest in Python

Ranvir Chhina
Tauk Blog
Published in
4 min readMay 11, 2022

When you are working with a large project, you need to able to write unit tests for your code with ease and have increased readability for your test methods. Although the Python standard library allows a user to write unit tests using the unittest framework, this framework is meant to be used at a smaller scale. It can lead to a lot of boilerplate code and does not have a lot of features that are required at scale when trying to publish a python package. For example, in one of my previous blog posts, I had to show how to execute python unit tests in parallel because unittest does not natively support it.

The Python community often chooses to use third party testing frameworks, which require less boilerplate code and have useful features built in. The aim of this article is to introduce PyTest package - as an alternative to unittest framework - and give an example based approach on how to use it to write and execute unit tests in Python.

Installing pytest

To install this package, you need to have python and its package manager pip installed in your system. You can install pytest with the following command

To verify that the installation worked, you can run the package in command line

If the package was installed successfully, the previous command will show you which pytest version was installed. If you run into any issues during pytest installation, you can leave a comment on this article.

Writing a Simple Test

Let us now write a simple test case to run a selenium test using pytest. In this test case, we will conduct sanity testing on the Google Home page and verify that it displays a Link to “Gmail” web application. Create a new python module and name it test_gmail.py.

The name of this module can be anything as long as it contains the “test” keyword in it.

Let us break down this pytest test case.

  • This module has a function called test_gmail_link_visible. This function can be discovered by the pytest framework as a test as long as its name contains the test_ prefix. You might have noticed that unlike unittest, we did not need need to create a TestClass extending unittest.TestCase. This is the first part where the boilerplate code was reduced.
  • We instantiate a Chrome WebDriver using the selenium package and navigate to the Google home page using driver.get(). After this we find a link with test “Gmail” and verify the URL that it points to.
  • The verification step involved using Python’s native assert statement and the in operator. pytest reuses a lot of Python operators in asserts unlike unittest which has JUnit inspired legacy functions like AssertEquals.

Running a Test

You can run this test using the pytest command line interface. To run all tests from all modules in current directory and its subdirectories you can execute the following command

To run a specific test method from a specific module

Test Fixtures

As with unittest, we need a way to use test steps that are atomic in nature and can be easily reused across test cases. In unittest, we specified the test fixture using setUp() and tearDown() methods. In pytest, any method can be reused by making it a fixture. To create a fixture:

  1. Annotate the function with the @pytest.fixture decorator
  2. Pass the fixture method name as a test method parameter

Since creating a driver and navigating to Google home page are steps that can be reused across tests, it can be useful to create fixtures for these.

In the above example, we created a fixture called driver and used it value in the test. When this test is run, the fixture is run before and the return value is cached. Whenever driver variable is requested within the test case for the first time, the value cached earlier is used.

Multiple Fixtures

Within the setUp() method of unittest framework, there can be multiple steps. If one of them fails, all the following steps might not execute leading to state that might cause failures in other test cases. This can be solved by declaring multiple fixtures for executing a single state altering task.

In the above example, we distributed driver creation and navigation into two separate fixtures. You might have noticed that the get_google fixture is re-using the driver fixture. This is exactly where the power of fixtures lies in. Fixtures can be built on top of each other.

Finalizing Fixtures

You might think that fixtures help can only help in re-using code that is run before test cases. But it can also be used to reuse steps after the test execution. This is analogous to the tearDown() method of unittest. To finalize a fixture, you can pause its execution, execute the test and then resume the fixture after test execution. This can be done using a very clever syntax using the yield statement.

Let us update the driver fixture to quit the WebDriver object after the test finishes execution.

In this updated fixture, the execution will pause after the yield statement. After the test finishes, the execution will resume and quit the WebDriver object.

Conclusion

This short guide shows you how to write a unit test using the pytest package and invoke the test cases using the command line. It also shows you how to write test fixtures, reuse them and finalize them to conserve memory and do cleanup actions.

Lastly, if you have any questions on this blog post, you can reach out to us by joining our Discord server:

--

--

Tauk Blog
Tauk Blog

Published in Tauk Blog

Enabling developers to efficiently diagnose, resolve, and optimize their automation tests.