Написание простого хука Pytest

Pytest — это моя среда тестирования Python из-за ее гибкости. Одной из его замечательных функций является возможность записывать хуки в различные моменты выполнения набора тестов. Все они могут быть ссылками через Документация по API. На работе у нас могут быть сотни тестов, и иногда изменения могут привести к сбою десятков тестов. Теперь давайте не будем слишком углубляться в «когда вы вносите изменения, только несколько тестов должны сломаться. Вы не должны видеть 30-40 неудачных тестов». Ну, конечно, это здорово с идеальным набором тестов, но иногда у вас просто не будет этого. Или вы будете вносить изменения в промежуточное программное обеспечение, которое влияет на все вызовы, и у вас будет масса сбоев. Когда у вас есть 30-40 тестов, если не только 10, вы обнаружите, что просеиваете множество выходных данных pytest, чтобы просто найти тесты, которые не прошли. Из-за этого давайте просто подключимся к выполнению pytests и запишем все наши неудачные тесты в failures.txt поэтому мы можем очень четко видеть, какие из наших тестов не удались.

Создать новый virtualenv и установить pytest в этом. я предполагаю Python3.6 Это должно быть все, что вам нужно.

Напишите простой тест, который мы принудительно провалим в файле tests.py

def test_failed():
    assert False
    
def test_passed():
    assert True

Создать conftest.py и добавьте следующий код.

import pytest

@pytest.hookimpl()
def pytest_sessionstart(session):
    print("hello")

Pytest автоматически подберет наш хук из conftest.py так же, как это было бы с приспособлениями.

Если мы побежим $ pytest tests.py мы можем увидеть результат следующим образом. (удалил некоторые = для краткости)

19:45 $ pytest tests.py 
hello
=======================...=================== test session starts 

Согласно API-документы мы можем видеть, что это был бы подходящий хук для создания нашего failures.txt файл, так что давайте сделаем это.

Меняйте крючок следующим образом


from pathlib import Path
from _pytest.main import Session


FAILURES_FILE = Path() / "failures.txt"

@pytest.hookimpl()
def pytest_sessionstart(session: Session):
    if FAILURES_FILE.exists():
        
        
        FAILURES_FILE.unlink()
    FAILURES_FILE.touch()

мне нравится использовать pathlib при работе с чем-либо на пути только потому, что это намного приятнее, чем os.path. Изменение логики довольно простое. Если файл уже существует, удалите его, а затем создайте новый.

Далее нам нужно написать хук, чтобы добавить ошибки теста к нашему failures.txt файл. Согласно API-документы pytest_runtest_makereport будет нашим желаемым крючком. Этот хук запускается сразу после запуска тестового примера и получает сам тестовый пример (Item), а также результат тестового примера (CallInfo). Добавьте следующее в conftest.py


from _pytest.nodes import Item
from _pytest.runner import CallInfo



@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item: Item, call: CallInfo):
    
    
    
    outcome = yield  
    result = outcome.get_result()
    if result.when == "call" and result.failed:
        try:  
            with open(str(FAILURE_FILE), "a") as f:
                f.write(result.nodeid + "\n")
        except Exception as e:
            print("ERROR", e)
            pass

Поскольку нам не нужно модифицировать сам отчет о тестировании, мы напишем наш как обернутый хук через hookwrapper=True. API-документы дайте отличный пример упорядочения вызовов ловушек, который является более подробным, чем мои комментарии.

В этот момент, если мы запустим $ pytest tests.py мы можем видеть, что наш единственный неудачный тест записывается в failures.txt

$ cat failures.txt 
tests.py::test_failed

Разработчики в вашей команде могут даже не заметить этот файл, поэтому давайте дадим им небольшое указание. Давайте добавим хук для печати направлений в конце запуска теста.
Снова просматривая API-документы кажется pytest_terminal_summary наш желаемый крючок.


from _pytest.runner import CallInfo
from _pytest.terminal import TerminalReporter


@pytest.hookimpl(hookwrapper=True)
def pytest_terminal_summary(
    terminalreporter: TerminalReporter, exitstatus: int, config: Config
):
    yield
    print(f"Failures outputted to: {FAILURE_FILE}")
    print(f"to see run\ncat {FAILURE_FILE}")

В нашем случае, я думаю, имеет смысл запускать все остальные хуки до запуска нашего, чтобы мы могли гарантировать, что наши направления будут последними, что напечатано на терминале. Мы снова будем использовать hookwrapper=True и поместите наш код ПОСЛЕ yield утверждение. В нашем случае мы ничего не делаем с результатом yield поэтому мы можем просто вызвать его и ничему не присвоить. С этим изменением кода запустите $ pytest tests.py снова и мы можем видеть следующее.

tests.py:3: AssertionError
Failures outputted to: failures.txt
to see run
cat failures.txt
=====================...== 1 failed, 1 passed in 0.04s=====...===

Я надеюсь, что это послужило хорошим примером использования написания пользовательских хуков в реальном мире. pytest. Не стесняйтесь обращаться ко мне с любыми вопросами или отзывами относительно этого поста.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *