Не понимаю, как использовать yield в автотестах
Изучаю автотестирование и возникла проблема. В одной статье написано, что "yield — это разделитель, все, что написано над ним, будет исполнено до теста, все, что ниже — после теста." и приведен пример написания фикстуры:
@pytest.fixture(autouse=True)
def get_driver(request):
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
request.cls.driver = driver
yield
driver.quit()
yield без каких-либо переменных прописан.
В другом месте я увидела другой пример:
@pytest.fixture(scope="session")
def browser():
driver = webdriver.Chrome(executable_path="./chromedriver")
yield driver
driver.quit()
Здесь уже yield driver.
Я не понимаю, когда нужно указывать переменную, а когда нет.
Ответы (2 шт):
@Nati, спасибо что добавили ссылки, а вот звездочки в коде вопроса зря, я уже думал что-то упустил из Python смотря на запись **yield driver** поэтому их (звездочки) лучше убрать. yield driver — это все равно что return driver (очень грубо но суть такая же) т.е. иногда в функциях Вы пишите просто return а иногда return value тут тоже самое можно yield а можно yield driver
Приведу пример на основе документации (только упрощу и return заменю на yield):
файл test_sample.py
import pytest
@pytest.fixture
def my_fruit():
yield "apple"
@pytest.fixture
def fruit_basket(my_fruit):
return ["banana", "apple"]
def test_my_fruit_in_basket(my_fruit, fruit_basket):
assert my_fruit in fruit_basket
Тут мы проверяем наличия банана в нашей корзине.
$ pytest
========================= test session starts =========================
platform linux -- Python 3.10.6, pytest-7.2.2, pluggy-1.0.0
rootdir: ...
collected 1 item
test_sample.py . [100%]
========================== 1 passed in 0.01s ==========================
А теперь я верну просто yield без банана т.е. так:
@pytest.fixture
def my_fruit():
yield
Результат:
$ pytest
========================= test session starts =========================
platform linux -- Python 3.10.6, pytest-7.2.2, pluggy-1.0.0
rootdir: ...
collected 1 item
test_sample.py F [100%]
============================== FAILURES ===============================
_______________________ test_my_fruit_in_basket _______________________
my_fruit = None, fruit_basket = ['banana', 'apple']
def test_my_fruit_in_basket(my_fruit, fruit_basket):
> assert my_fruit in fruit_basket
E AssertionError: assert None in ['banana', 'apple']
test_sample.py:24: AssertionError
======================= short test summary info =======================
FAILED test_sample.py::test_my_fruit_in_basket - AssertionError: assert None in ['banana', 'apple']
========================== 1 failed in 0.05s ==========================
В данном случае мы видим упавшие тесты. Т.е. В общем случае вопрос не сильно связан с тестами, а больше с возвращаемым значением. Если нам где-то нужен driver мы его возвращаем, не нужен делаем просто yield отличие которого от return только лишь в том что при повторном запуске сработает не этот а следующий за ним yield если он есть, например так:
def my_fruit():
yield 'apple' # <--- вернет в первый раз
yield 'kivi' # <--- вернет во второй раз
Но конкретно в фикстурах yield должен быть один!
____________ ERROR at teardown of test_my_fruit_in_basket _____________
fixture function has more than one 'yield':
@pytest.fixture
def my_fruit():
yield "apple"
yield "kivi"
Это связано с освобождением ресурсов после выполнения кода, например: закрытие driver
Одним словом, не знаете возвращать или нет — возвращайте, много не потеряете.
Надеюсь, моих объяснений окажется достаточно, чтобы двигаться дальше.
Данная запись фикстуры:
@pytest.fixture(autouse=True)
def get_driver(request):
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
request.cls.driver = driver
yield
driver.quit()
подразумевает такое использование в тесте:
def test_1(request):
some_driver = request.driver
...
Что происходит в данном случае? В таком сценарии есть другая фикстура request, чтобы обратиться к этой фикстуре - она указывается в аргументах тест-кейса, а фикстура get_driver вызывается автоматически, благодаря использованию параметра autouse=True, в фикстуре get_driver мы тоже используем фикстуру request (фикстуры могут использовать другие фикстуры), и в данном случаем мы модифицируем объект request, предоставляемый той фикстурой, благодаря чему driver становится доступным в тесте.
Другая запись фикстуры
@pytest.fixture(scope="session")
def browser():
driver = webdriver.Chrome(executable_path="./chromedriver")
yield driver
driver.quit()
Предполагает другой сценарий использования в тесте:
def test_1(browser):
some_driver = browser
...
В данном случае мы указываем фикстуру в параметрах тест-кейса, в качестве значения этого параметра мы получим непосредственно то, что фикстура вернула - через операторы return или yield - то есть объект driver. После завершения тест-кейса фреймворк pytest снова пройдет по фикстурам и выполнит код который указан после оператора yield (в случае если таковой имеется).