Python

Python pytest tutorial (Test your scripts with ease)

Testing an application before launching it into the market is essential to check whether your program works fine or crashes unexpectedly under certain conditions.

Testing the code increases your or the team’s confidence that your code is behaving as per your expectation.

Application testing thus became a standard skill every programmer must have to become a competent application engineer or a full-stack developer.

This article will give a complete knowledge of Python’s code testing through the Python pytest module.

 

 

What is Python pytest?

Pytest is one of the most popular testing frameworks that help developers efficiently write, test, and check applications, APIs, and libraries in Python.

This testing module provides scalable test cases for Python apps that use databases, dependencies, and UI.

Pytest’s primary intention was to allow you to write test codes for APIs.

It enables you to write test cases ranging from simple unit testing to complicate functional testing. It is a matured, feature-rich testing tool, which comes with some exceptional characteristics.

  • It is easy to install and use.
  • It does not require additional API to use.
  • You can use it to run unit tests and doc tests.
  • It has many useful built-in plug-ins for testing.
  • It can provide valuable application failure or execution negligence information without using an additional debugger.
  • You can automatically detect the tests or skip test segments through this tool.
  • You can execute specific test or its subset from the program using this tool.
  • It allows running tests in parallel.

 

Install pytest for Python

Installing pytest in your system is easy using pip. Simply open your terminal and type the following command:

pip install pytest

Once the installation gets completed, you can confirm whether pytest got successfully installed or not. Use the help attribute of it using the command:

py.test -h

Output

This output shows installation of Pytest in Python

 

How to use pytest?

We can use the assert keyword that helps in debugging code or check whether a particular assertion or test will succeed or fail. Assertions return either True or False based on the success or failed test.

Also, we need to import the pytest module in our program using the import statement. Here is a code snippet showing how to use it.

import pytest

def test_method1():

	a = 6

	b = 8

	assert a+1 == b, "test failed"

	assert a == b, "test failed"

def test_method2():

	a = 6

	b = 8

	assert a+2 == b, "test succeed"

Output

This output shows how to use Pytest in Python

 

Run pytest with specific Python version

You can run pytest with a specific Python version by using the pyenv module. Incorporating pyenv in your module will allow you to switch between different versions of Python.

Hence, you can test all the associated projects of those versions using the pytest.

 

Pytest fixtures

Fixtures in pytest are a means of delivering data, test replicas, or creating a state setup for your tests. These are functions that help in returning a broad spectrum of values.

Each Python program test that depends on a fixture has to acknowledge the fixture explicitly as an argument.

You can use fixtures instead of class xUnit testing style setup & teardown techniques wherein a particular part of code gets executed for each test case. The primary reasons for using the Python Fixtures are:

  • You can use fixtures instead of class xUnit testing style setup & teardown techniques wherein a particular part of code gets executed for each test case.
  • You can implement it modularly. There is no hardcore learning curve for implementing it.
  • They are reusable and hence save a lot of testing time.
  • You can use it for simple testing and complex testing.
  • Fixtures have various scopes and lifetimes. Apart from the default function scope, you can also use it for class, module, and package scopes.

Fixtures are good when we want to extract the test object where we want to use multiple test cases. But in most cases, our program needs a little bit of modification in data.

There, the fixtures are not proven as the best solution.

 

Pytest Conftest

Fixtures are the most powerful features of a pytest. Through fixtures, you can define or set up certain pre-configurations, conditions, and layouts to your test script file for checking various application features like a database connection or handling data through APIs from other sources.

Now, if we wish to share the fixtures to multiple files, there we will need to use the conftest.py file.

If we specify the Conftest.py file in our scripts, then we can access all the test classes & their associated modules from our project directory so that we can share all configurations & optimize our script.
Example:

@pytest.fixture()

def fixture():

    return "some code"

 

Pass pytest arguments when invoked via Command line

We can pass arguments to test a program that gets invoked via command line argument. Here is a code snippet showing how to do it.

def test_compute(param1):

assert param1 < 4

Now change the content of confest.py file with the following code:

def pytest_addoption(parser):

    parser.addoption("--all", action = "store_true", help = "this attribute runs all combinations")

def pytest_generate_tests ( metafunc ):

    if "param1" in metafunc.fixturenames:

        if metafunc.config.getoption("all"):

            end = 6

        else:

            end = 2

        metafunc.parametrize("param1", range (end))

Output

This output shows how to Pass pytest arguments in Python

 

Skip a method using pytest marker

Often we do not need specific methods or sections to test because they are either in the prototype stage of development or that particular feature becomes obsolete and is no longer in use.

So, we skip those modules. Since pytest can be used for creating test cases, we can skip a selected testing method from getting executed in pytest.

The test file method comes with a naming convention that starts with test_ or ends with _test keyword. Every line of code that needs has to be inside a method that will have a name starting with test keyword.

Also, it is mandatory that each method must have a unique name.
Now comes the role of a pytest marker.

A marker helps in setting metadata, such as, different properties, characteristics & attributes for test functions. The markers remain attached to the test function(s) in the form of function decorators that programmers have to mention along with them.

Some built-in markers that pytest programmers should use are xfail, skip, etc. In this case, we have to use the skip marker in the pytest decorator to skip a method.
Syntax:

@pytest.mark.skip(reason = "provide a reason to skip this test case.")

def test_case():

    ....

Here is a code snippet showing how to do it.

import pytest

@pytest.mark.skip(reason = "The feature became obsolete ")

def test_new_feature():

    print("New feature")

def test_logout():

    print("Test log out")

Output

This output shows how to skip a method using pytest in Python

 

Pytest failures

Often pytest fails when the conditions or any particular logic do not meet the requirement as expected or as provided in the test cases.

Pytest will highlight a failed test with descriptions and pointers on where the test assertions did not meet the requirement.

For tests that fail, pytest generates a detailed report of the breakdown as a failure.

Here is a code snippet that tells us that the assert statement leads to failure because the left hand side and the right hand side value/constant did not matched (as the == operator relates both side). So, it generates false and the test failed.

import pytest

def test_method1():

	a = 6

	b = 8

	assert a+1 == b, "test failed"

	assert a == b, "test failed"

def test_method2():

	a = 6

	b = 8

	assert a+2 == b, "test succeed"

Output

This output shows Pytest Failures in Python
Again, pytest error and failure are two different things.

While a failed test will generate reports of where the test fails, a pytest error in the test allows you to handle it by raising an exception. Here is a code snippet showing how they differ.

import pytest

def test_fail():

    assert 2 == 6

@pytest.fixture

def fixing_thru_exception():

    raise Exception('Constant Not Matched')

def test_error(fixing_thru_exception):

    assert fix == 6

Output

This output shows Pytest Failures in Python

 

Generate HTML report

For generating a test report as an HTML file with the Pytest framework, we should install a separate plug-in (pytest-html) that will work with the pytest module.

For installing, we shall execute the pip command:

pip install pytest-html 
Next, for creating the report, we have to run the command:
pytest –html = report.html

Once you execute this command and all the test cases got passed, or got skipped or shows warning but runs, you can see a file name “report.html” that has been generated within your project directory.

If you are using IDEs like PyCharm, you can easily check that out in the left window pane of your IDE.
Output

This output shows report.html file for Pytest
Now, if you run this HTML file, you can see the details of the test along with environment where the program got tested, number of test cases passed or skipped, etc.

 

Common pytest Plugins

Plug-ins plays a significant role in doing additional tasks along with the pytest module. As we have seen in the previous example, the pytest-html plug-in can generate an HTML report for pytest.

Here is a list of a few more pytest plug-ins that we can use while implementing the pytest framework for testing.

  • pytest-cov: Code coverage is an essential concept in testing. There can be several reasons to measure the code coverage during a Python test. Code coverage helps understand and determine which portions of code got executed by our tests. With the help of a code coverage tool, programmers or testers can identify aged or unused code, reveal test deletions, and yield a quality measure of our code.
  • pytest-mock: It is another pytest plug-in that revolves around the standard unittest.mock package under the fixture. It produces patching objects & functions by substituting them through a “Mock” object. It is easier, more tidy, and simpler to use than that of the unittest.mock.patch. It also delivers spy and stub utilities not available with the unittest module.
  • pytest-django: Building web apps have become simpler & high-class because of Django. Apart from excellent documentation and community support, programmers can write a test in Django and use django.test.TestCase, which is a subclass of unittest.TestCase. This plug-in simplifies your Django app’s testing techniques & delivers some suitable fixtures.
  • pytest-asyncio: This plugin has now become a part of the standard library for writing asynchronous code, allowing IO-bound applications to render at their best, and perform the test for asynchronous programs. It delivers fixtures to inject the asynchronous event loop & allows employing unused TCP ports within the test cases. It also permits constructing of async fixtures.
  • pytest-clarity: Although pytest’s testing output about the test and test failures are very much detailed and clear, compared to unit test, programmers can also tune the amount of output information by using this plugin. Furthermore, this plugin improve pytest’s output by encouraging a more coherent definition for tests failures. Pytest-clarity enhances the test failures and output by delivering useful hints and displays unified/split differences. Lastly, tracking a failed test becomes much simpler & manageable through this plugin.
  • pytest-randomly: Generating interdependency between tests enables a programmer to run multiple test cases in parallel. Typically, a unit test case checks a unit of behaviour. It becomes a nice practice as each test remains isolated. But if you unknowingly create dependent tests, that is where pytest-randomly can come to the rescue. This plugin orders the tests by resetting the random seed to create a repeatable number for each test.

 

Pytest vs. Unittest

There has a proper difference between pytest and unittest modules.

PytestUnittest
Pytest requires less set of code to make the complete testing.Unittest requires many lines of codes compared to pytest to make a successful testing.
Pytest has many rich built-in features.Features in unittest are comparatively lesser in unittest.
Pytest is easier to work with and compact.Unittest is slightly older and takes time to code and work with compared to pytest.
It is a powerful testing framework that allows testing an app at all levels. It also provides test automation but is not a part of the standard module.It comes under the standard module bundled with Python. It supports heavy automation & accumulation of testing.

 

Conclusion

We hope this article has given a crisp idea of what the pytest module does and how to use it. We have also gathered insight on how to install it and pass arguments in the command line for testing.

Then, we discussed its fixtures and markers and understood when a test failure occurs.

Finally, we have generated report and discuss the well-known plugins through which we can work while dealing with pytest.

Leave a Reply

Your email address will not be published.