Skip to main content

Command Palette

Search for a command to run...

#4 - Pytest concept

Published
3 min read
S

• Possess over 14 years of experience in Quality Engineering, specializing in building test frameworks for complex systems including web applications, REST APIs, and core cloud infrastructure on platforms like Akamai's Linode and Azure.

• Skilled in the development and improvement of automation frameworks for various Web applications, service APIs displaying proficiency in TestNG, PyTest, Selenium, Rest Assured, Jenkins pipeline.

pytest is one of the most widely adopted testing frameworks in the Python ecosystem. It provides a clean, expressive, and highly extensible way to write tests—ranging from simple unit tests to large-scale API and integration test suites.

Tests are written as regular functions and classes, assertions use native Python syntax, and structure is driven by conventions rather than rigid frameworks. This makes tests easy to read, easy to maintain, and straightforward to scale as projects grow.


conftest

conftest.py is a pytest configuration and dependency injection file.

  • Define shared fixtures

  • Configure test-wide behavior

  • Expose fixtures without explicit imports

  • Control fixture visibility by directory scope

Pytest automatically discovers conftest.py files by walking up the directory tree.

Fixtures defined in tests/conftest.py are:

  • Available to all tests under tests/

  • Imported implicitly

  • Resolved via fixture dependency injection

conftest is used for

  1. Shared Fixture

  2. Environment and confguration setup

    1. Base URLs

    2. Environment selection (--env=dev)

    3. Auth tokens

    4. Sessions

  3. API Client/Sessions

  4. Pytest Hoooks and Options

    1. pytest_runtest_setup

    2. pytest_sessionstart

conftest should not be used for

  1. Test Logic

  2. Assertion

  3. One-off fixture used by a single test

  4. Business logic

Rules

  • Fixtures apply downward only

  • Closest conftest.py used

  • Enables bounded context per domain

tests/
├── conftest.py          # global fixtures
├── users/
│   ├── conftest.py      # user-specific fixtures
│   └── test_users.py

Fixture

A fixture is a dependency provider.

  • Setup (before test runs)

  • Reuse (same setup across many tests)

  • Teardown (cleanup after test)

Key idea:

  • Test does not create the user

  • Test declares what it needs

  • pytest injects the dependency

  • Fixtures can depend on other fixtures

Fixture Scope

  • function (default) - Per test function

  • class - Per test class

  • module - Per test file

  • package - Per folder

  • session - Entire test run

Setup and teardown using yield fixture

@pytest.fixture
def temp_user(user_client):
    user = user_client.create_user()
    yield user
    user_client.delete_user(user["id"])

Execution order:

  1. Code before yield → setup

  2. Test runs

  3. Code after yield → teardown (even if test fails)

Fixture Parametrization

Fixtures can produce multiple variants.

  • Same test runs twice

  • Different fixture values

  • Clean separation of test logic vs data

@pytest.fixture(params=["admin", "user"])
def role(request):
    return request.param
def test_access(role):
    ...

Fixture Override & Conftest

conftest.py

  • Central place for shared fixtures

  • No imports needed

  • Scoped by directory tree

Overriding fixtures

  • Lower-level conftest.py overrides higher ones.

  • Env-specific behavior

  • Test-specific customization


Pytest Execution

At a high level, pytest follows a simple flow:

  1. Find tests

    1. Pytest looks for test files, functions, and classes that follow its naming rules.

    2. Files starting with test_ or ending with _test.py

    3. Functions starting with test_

    4. Classes starting with Test

  2. Prepare test requirements

    1. If tests use fixtures, pytest figures out what each test needs and builds a dependency plan.
      Fixtures are set up in the correct order before the test runs.
  3. Run the tests

    1. Pytest executes the tests one by one.
      During execution:

      1. Fixtures are created

      2. Test code runs

      3. Assertions are evaluate

      4. If something goes wrong, the test is marked as failed or errored.

  4. Report the results After execution, pytest shows a summary of the results.

    1. Passed tests

    2. Failed tests

    3. Skipped tests

For failures, pytest also shows error messages and stack traces to help with debugging.