#4 - Pytest concept
• 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
Shared Fixture
Environment and confguration setup
Base URLs
Environment selection (--env=dev)
Auth tokens
Sessions
API Client/Sessions
Pytest Hoooks and Options
pytest_runtest_setup
pytest_sessionstart
conftest should not be used for
Test Logic
Assertion
One-off fixture used by a single test
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:
Code before yield → setup
Test runs
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:
Find tests
Pytest looks for test files, functions, and classes that follow its naming rules.
Files starting with test_ or ending with _test.py
Functions starting with test_
Classes starting with Test
Prepare test requirements
- 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.
- If tests use fixtures, pytest figures out what each test needs and builds a dependency plan.
Run the tests
Pytest executes the tests one by one.
During execution:Fixtures are created
Test code runs
Assertions are evaluate
If something goes wrong, the test is marked as failed or errored.
Report the results After execution, pytest shows a summary of the results.
Passed tests
Failed tests
Skipped tests
For failures, pytest also shows error messages and stack traces to help with debugging.
