【问题标题】:Pytest how to call a function with fixture argument directlyPytest如何直接调用带有fixture参数的函数
【发布时间】:2021-01-03 08:21:54
【问题描述】:

我正在为网络应用构建一个测试套件。我正在使用如下固定装置:

import pytest
from selenium import webdriver
from common import Common

@pytest.fixture(scope='module')
def driver(module, headless=True):
    opts = webdriver.FirefoxOptions()
    opts.add_argument('--headless') if headless else None
    driver = webdriver.Firefox(options=opts)
    driver.get('http://localhost:8080/request')
    yield driver
    driver.quit()

def test_title(driver):
    assert driver.title == 'abc'

if __name__ == '__main__':
    test_title() #what I need to execute to see if everything is fine

假设我需要通过直接在if __name__ == '__main__': 中运行此模块来查看我的test_title 函数是否正在做它需要做的事情。如何使用作为参数传入的驱动程序调用test_title()

像下面这样调用test_title

if __name__ == '__main__':
    test_title(driver(None, False))

python 产生下面提到的错误:

(virtual) sflash@debian:~/Documents/php/ufj/ufj-test$ ./test_r*
Traceback (most recent call last):
  File "./test_request.py", line 30, in <module>
    test_empty_all(driver(None, headless=True))
  File "/home/sflash/Documents/php/ufj/ufj-test/virtual/lib/python3.7/site-packages/_pytest/fixtures.py", line 1176, in result
    fail(message, pytrace=False)
  File "/home/sflash/Documents/php/ufj/ufj-test/virtual/lib/python3.7/site-packages/_pytest/outcomes.py", line 153, in fail
    raise Failed(msg=msg, pytrace=pytrace)
Failed: Fixture "driver" called directly. Fixtures are not meant to be called directly,
but are created automatically when test functions request them as parameters.
See https://docs.pytest.org/en/stable/fixture.html for more information about fixtures, and
https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code.

【问题讨论】:

  • Pytest 测试应该通过在命令行上调用 pytest 来执行。您可以调用pytest.main()(使用命令行选项作为参数),但这与直接调用 pytest 完全相同(例如,收集所有测试,无论它们是否在当前模块中)。
  • @MrBeanBremen 我不知道,谢谢!但是还有很多其他方法可以解决这个问题,比如直接在 main.js 中创建另一个驱动程序。但我想知道是否有一种方法可以直接以老式方式使用 python 解释器运行它。
  • 好吧,调用python -m pytest(或python -m pytest test_xxx.py,如果你只想运行一个特定的测试)会做你想做的事,除非我没有正确理解你。
  • @MrBeanBremen 抱歉,我需要直接运行它,如“./test_request.py”或(“python3 test_request.py”)。这或多或少是一个好奇的问题,如果仅通过更改夹具行为更改源代码是否可以调用driver 并将其发送到test_title
  • 好吧,正如我所写,您可以将 pytest,main() 放入您的 __main__ 部分,这与在命令行上通过 pytest 调用它的效果相同。

标签: python-3.x selenium pytest


【解决方案1】:

正如在 cmets 中所讨论的,fixture 不能直接调用 - 它们只能与 pytest 一起使用。

要直接从您的代码中调用测试,您可以在__main__ 部分中调用pytest.main(),这与在命令行中调用pytest 的效果相同。任何命令行选项都可以作为参数添加到调用中(作为列表),例如:

if __name__ == '__main__':
    pytest.main(['-vv', 'test.py::test_title'])

要使用涉及 pytest 的驱动程序(这是您的意图),您必须提取驱动程序逻辑并从夹具和主程序中分别调用它:


import pytest
from selenium import webdriver
from common import Common

def get_driver(headless=True):
    opts = webdriver.FirefoxOptions()
    opts.add_argument('--headless') if headless else None
    driver = webdriver.Firefox(options=opts)
    driver.get('http://localhost:8080/request')
    return driver
):

@pytest.fixture(scope='module')
def driver(module):
    yield get_driver()
    driver.quit()

def test_title(driver):
    assert driver.title == 'abc'

if __name__ == '__main__':
    driver = get_driver()
    test_title() 
    driver.quit()

请注意,这仅在测试功能不依赖任何 pytest 特定的东西(例如自动应用的固定装置)时才有效。
另请注意,您不能像在示例中那样在夹具中使用参数,因为您无法提供参数。相反,您可以使用parametrized fixtures

【讨论】:

  • 我会在这个答案的开头添加pytest.main 的调用,以便为未来的读者指出正确的解决方案。
猜你喜欢
  • 2019-11-18
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 2020-05-17
  • 2017-12-25
相关资源
最近更新 更多