Product Engineering

Pytest – One Solution for Unit, Functional and Acceptance Tests

Pytest

Python: A tester’s choice

Python is a general purpose, dynamic and flexible language, hence a lot of applications are being developed using Python. From a tester’s perspective, it has readily available modules and libraries which make scripts creation a lot easier. Tests can be written as xUnit-style classes or as functions. It provides full fledge automation testing solution for any sort of project cause and It is capable enough to perform unit, functional, system and BDD testing.

Pytest: Best among all python testing frameworks

Pytest is a python testing framework which provides a single solution for unit, functional and Acceptance testing.
It is popular than the other available frameworks because of its attractive features. Below are some of the features of Pytest:

  • It offers test design with no boilerplate
  • It does not require separate methods for assertion like  assertEquals, assertTrue, assertContains
  • Tests can be parametrized which reduces code duplication
  • Pytest can run tests written in unittest, doctest, autres and nose
  • 150+ external plugins available to support all sorts of functional testing
  • Plugins available like pytest-BDD and pytest-konira for writing tests for Behaviour Driven Testing
  • It works wonder for GUI automation testing, when used along with testing tools like selenium webdriver or splinter

In short pytest is a one stop solution for all sort of python testing be it unit, functional, highly complex functional or acceptance tests (BDD).

Top Most Pytest Features and properties

Pytest Fixtures: Nervous system of pytest
Fixtures are the key concept in pytest which can essentially provide baseline for test creation and execution. To declare any method as fixture just put the annotation for the method “@pytest.fixture” and put them in “Conftest.py”

Fixture example:

@pytest.fixture
def open_browser():
driver = webdriver.Firefox()
driver.get(“http://www.python.org”)
assert “Python” in driver.title

The above designed fixture will be available for the whole project provided this should specified in project directory conftest.py file.

  • Conftest.py file contains all configuration settings, all defined fixtures, hooks implementations and it is applicable to the directory level. They get loaded by default whenever tool is invoked.

Some key points on fixtures:

  • Fixtures have names and can be called from anywhere in the project, modules, classes and tests
  • Fixtures can return or not return any value or just execute the specified steps in it.
  • Fixtures can be passed as function arguments and in that case the returning value of fixture will be available in the mentioned method.
  • Fixture can be specified in directory level conftest.py file. Can be called from any method and it will execute the steps specified in it.
  • A fixture can take multiple fixtures, and each fixture triggers other fixture, thus serves a modular approach.
  • Fixtures can be scoped as per the need. This is a good practice keeping in mind time-expensiveness. Scope can be “session”, “module”, “class” and “function”.

Request object: Introspect agent
This is one of the useful features to search or introspect the “requesting item”. It can introspect from test function, class, module, or session. Items specified in config file or returning by some other fixtures can be used efficiently by the called fixture by “getattr” function. Just check the below mentioned fixture:

  • Example:

@pytest.fixture
def driver(request, browser_type):
“””return a webdriver instance for testing
        try:
_driver = getattr(webdriver, browser_type)()
except AttributeError as error:
logger.info(“Browser type %s unavailable!”, browser_type)
raise AttributeError
return _driver
Finalization code: Setting up of teardown
Fixture can be used for teardown as well. This can be achieved by using “yield” keyword. Just put the fixture with the annotation “@pytest.yield_fixture“ and put the steps after “yield” keyword in the fixture. And whenever fixture will go out of scope the steps after the “yield” keyword will serves as  teardown process. Have a look at the below modified steps of the “driver” fixture.

  • Example:

@pytest.yield_fixture
def driver(request, browser_type):
“””return a webdriver instance for testing
        try:
_driver = getattr(webdriver, browser_type)()
except AttributeError as error:
logger.info(“Browser type %s unavailable!”, browser_type)
raise AttributeError
yield _driver
logger.info(‘Finishing test”)
logger.info(‘*************************’)
_driver.quit()

In the above mentioned fixture whenever “browser_type” is not available the driver instance will be quit.

Fixture parametrization: Enhances reusability
Fixtures can be parametrized and can be executed multiple times with different set of data, the same way as a normal function is executed.

Usefixtures: Call for fixture from anywhere
One way by which fixtures can be made available anywhere in the project is by calling them by using the decorator “@pytest.mark.usefixtures(“fixture_1”, “fixture_2”)”.

Autouse fixture: Mark the fixture for  all
AF are the fixtures methods which get invoked without “usefixtures” decorator or “funcgars”.
Any fixture can be registered for autouse. Just need to put keyword autouse with “True” flag. “pytest.fixture(scope=”module”,autouse=True)”. Fixture will run for a class or test or module as mentioned in the scope. If they are defined in conftest then they will be invoked by the all tests present below the directory. These fixtures are particularly useful to set applicable global settings for the test session.

Auto Test Discovery in Pytest: Ease of execution
One of the very useful features is auto test discovery in pytest. Its means it detects all the tests once execution command is invoked,  user only need to specify the test modules and test with a prefix “test_*.” while designing . Command line arguments can be specified with tests names, directories, node ids and file names. In case of absence of any command line arguments then collection with start from specified ‘testpaths’ (provided they need to be configured). This feature help in running all the tests, multiple tests in groups, single test, and tests belong to specific directories. Alternatively test can be organized in specific folder structure as per the modules and thus can be executed as per the need.