Fixture trong Pytest
Fixture là một cơ chế trung tâm trong Pytest, cho phép chia sẻ dữ liệu, trạng thái hoặc tài nguyên giữa các test và fixture khác. Một hàm test hoặc fixture khác có thể yêu cầu sử dụng fixture thông qua tham số hàm. Ví dụ:
def test_output(capsys):
print("hello")
captured = capsys.readouterr()
assert captured.out == "hello\n"
Một fixture cũng có thể phụ thuộc vào fixture khác:
@pytest.fixture
def db_session(tmp_path):
db_file = tmp_path / "database.sqlite"
return connect_to_db(str(db_file))
@pytest.fixture – Định nghĩa fixture
Được dùng như một decorator để đánh dấu một hàm là fixture. Cú pháp:
@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)
- scope: Phạm vi hoạt động của fixture –
"function"(mặc định),"class","module","package"(thử nghiệm), hoặc"session". - params: Danh sách giá trị để tạo nhiều phiên bản test từ cùng một fixture.
- autouse: Nếu
True, fixture tự động được kích hoạt mà không cần khai báo tường minh. - ids: Tên tùy chỉnh cho từng giá trị trong
params, giúp dễ đọc kết quả test. - name: Đặt tên riêng cho fixture, hữu ích khi muốn tránh xung đột tên trong cùng module.
Fixture có thể trả về giá trị bằng return hoặc yield. Với yield, phần code sau đó sẽ được thực thi như bước dọn dẹp dù test thành công hay thất bại.
Các Built-in Fixture Chính
config.cache – Lưu trữ trạng thái giữa các lần chạy
Cho phép lưu và lấy lại dữ liệu giữa các lần chạy test, thường dùng trong plugin hoặc setup nâng cao.
cache.get(key, default): Lấy giá trị theo khóa; trả về mặc định nếu không tồn tại.cache.set(key, value): Lưu giá trị với kiểu dữ liệu Python cơ bản (dict, list, str...).cache.makedir(name): Tạo thư mục tạm để lưu file (ví dụ: dump database).
capsys & capfd – Bắt đầu ra stdout/stderr
Dùng để kiểm tra đầu ra in ra màn hình.
def test_print(capsys):
print("Testing capture")
captured = capsys.readouterr()
assert "Testing" in captured.out
capsys: Bắt dạng text từsys.stdout/sys.stderr.capsysbinary: Bắt dạng bytes.capfd: Bắt output từ file descriptor (phù hợp với lệnh hệ thống).capfdbinary: Phiên bản bytes củacapfd.
doctest_namespace – Hỗ trợ doctest
Cung cấp namespace cho các ví dụ trong docstring. Thường dùng với autouse=True:
@pytest.fixture(autouse=True)
def add_numpy(doctest_namespace):
doctest_namespace["np"] = numpy
request – Truy cập ngữ cảnh test
Cho phép truy cập thông tin runtime như tên test, tham số, cấu hình…
def test_info(request):
print(f"Running {request.node.name}")
if request.cls:
print(f"In class {request.cls.__name__}")
Một số thuộc tính quan trọng:
request.function: Hàm test hiện tại.request.module: Module chứa test.request.config: Đối tượng cấu hình pytest.request.param: Giá trị tham số nếu fixture được parameter hóa.request.addfinalizer(): Đăng ký hàm dọn dẹp.request.getfixturevalue('name'): Gọi fixture động (thay thếgetfuncargvalueđã lỗi thời).
pytestconfig – Truy cập cấu hình toàn cục
Trả về đối tượng Config để kiểm tra cờ dòng lệnh:
def test_verbose(pytestconfig):
if pytestconfig.getoption("verbose") > 0:
print("Verbose mode enabled")
record_property & record_testsuite_property – Ghi thuộc tính vào báo cáo
Dùng để thêm metadata vào kết quả test:
def test_with_metadata(record_property):
record_property("issue", "BUG-123")
record_property("environment", "staging")
record_testsuite_property có phạm vi session, dùng để ghi thông tin toàn bộ suite (ví dụ: JUnit XML).
caplog – Kiểm tra log
Bắt và kiểm tra các thông điệp log:
def test_logging(caplog):
with caplog.at_level(logging.INFO):
some_function_that_logs()
assert "User logged in" in caplog.text
assert ("my_logger", logging.ERROR, "Failed") in caplog.record_tuples
Các thuộc tính:
caplog.records: Danh sách đối tượngLogRecord.caplog.text: Chuỗi log đã định dạng.caplog.messages: Danh sách message đã xử lý.caplog.clear(): Xóa log đã bắt.caplog.set_level(): Điều chỉnh mức log.
monkeypatch – Thay đổi tạm thời hệ thống
Dùng để mock biến môi trường, thuộc tính, hàm…
def test_env_var(monkeypatch):
monkeypatch.setenv("API_KEY", "fake123")
assert get_api_key() == "fake123"
def test_attribute(monkeypatch):
monkeypatch.setattr(os, 'getcwd', lambda: "/fake/path")
assert os.getcwd() == "/fake/path"
Tất cả thay đổi sẽ tự động hoàn tác sau khi test kết thúc.
tmp_path & tmpdir – Thư mục tạm
Cung cấp đường dẫn đến thư mục tạm duy nhất cho mỗi test:
def test_write_file(tmp_path):
data_file = tmp_path / "sample.txt"
data_file.write_text("Hello")
assert data_file.read_text() == "Hello"
tmp_path: Trả về đối tượngpathlib.Path(ưu tiên dùng).tmpdir: Dạng cũ, dùngpy.path.local.
Các factory tương ứng (tmp_path_factory, tmpdir_factory) cho phép chia sẻ thư mục tạm ở phạm vi lớn hơn (ví dụ: module).
recwarn – Kiểm tra cảnh báo (warnings)
Ghi lại các cảnh báo Python phát sinh trong test:
def test_deprecation(recwarn):
deprecated_function()
assert len(recwarn) == 1
w = recwarn.pop(DeprecationWarning)
assert "deprecated" in str(w.message)
Hữu ích để đảm bảo mã đang di chuyển đúng hướng (ví dụ: xử lý DeprecationWarning).
testdir – Test plugin và nội bộ pytest
Dành cho việc kiểm thử plugin hoặc mở rộng pytest. Yêu cầu bật plugin:
# conftest.py
pytest_plugins = ["pytester"]
Cung cấp nhiều phương tiện để tạo file, chạy pytest nội bộ, kiểm tra đầu ra:
def test_plugin(testdir):
testdir.makepyfile("""
def test_something():
assert True
""")
result = testdir.runpytest()
result.assert_outcomes(passed=1)
Các phương thức chính: makepyfile(), runpytest(), inline_run(), parseconfig(), runpython().