In simple terms, Dependency Injection (DI) in Pytest means that your test functions don't have to worry about creating the tools they need; they just "ask" for them by name in their arguments.
Pytest acts as a delivery service: it sees what you've asked for, finds the corresponding fixture, runs it, and "injects" the result into your function.
1. The "Request by Name" Pattern
In standard Python, if a function needs an object, you usually create it inside the function or pass it manually. In Pytest, you simply name the fixture as a parameter.
import pytest
# The "Provider" (The Fixture)
@pytest.fixture
def sample_data():
return {"id": 1, "name": "Gemini"}
# The "Consumer" (The Test)
def test_data_integrity(sample_data):
# You never called sample_data(). Pytest did it for you.
assert sample_data["name"] == "Gemini"
2. Layered Injection (Fixtures requesting Fixtures)
DI becomes really powerful when fixtures start depending on other fixtures. Pytest builds a Dependency Graph to figure out the correct order of execution.
@pytest.fixture
def database_connection():
return "Connected to DB"
@pytest.fixture
def user_record(database_connection):
# This fixture 'asks' for the database_connection
return {"status": database_connection, "user": "Admin"}
def test_user_status(user_record):
assert user_record["status"] == "Connected to DB"
Pytest resolves this like a puzzle:
-
Test asks for
user_record. -
Pytest sees
user_recordneedsdatabase_connection. -
Pytest runs
database_connectionfirst, then passes the result touser_record, then passes that to the test.
3. The "Setup-Teardown" Injection
DI isn't just about passing data; it’s about managing a lifecycle. When you use yield, Pytest injects the value but keeps the function "alive" to clean up later.
import os
@pytest.fixture
def temp_file():
# SETUP: Create a file
f = open("test.txt", "w")
f.write("Hello World")
f.close()
yield "test.txt" # INJECTION: Hand the filename to the test
# TEARDOWN: Delete the file after the test finishes
if os.path.exists("test.txt"):
os.remove("test.txt")
def test_file_reading(temp_file):
with open(temp_file, "r") as f:
assert f.read() == "Hello World"
4. Why is this useful?
-
Decoupling: Your tests don't need to know how a database is set up or where a temp file is created. They just need the result.
-
Reusability: You can write one
clientfixture and inject it into 100 different test files. -
Cleanliness: Your test functions stay focused on assertions (logic) rather than configuration (boilerplate).
Summary of the Flow
-
Define: You create a function with
@pytest.fixture. -
Request: You add that function's name as an argument to your test.
-
Inject: Pytest executes the fixture and swaps the argument name for the actual return value.

浙公网安备 33010602011771号