如何从 pytest_addoptions 访问 pytest conftest 中的命令行输入并在夹具参数中使用它?

How do I access the command line input in pytest conftest from the pytest_addoptions and use it in fixture params?

我有一个 conftest 文件来处理在 pytest 中 运行ning 测试时 selenium 驱动程序的设置和拆卸。我正在尝试添加命令行选项以确定我是 运行 本地内置 selenium 和网络驱动程序还是远程 selenium 服务器和驱动程序等...

我添加了一个名为 "runenv" 的命令行选项,我正在尝试从中获取通过命令行输入的字符串值以确定系统是否应该 运行 本地或远程 webdriver 配置.这允许测试人员在他们自己的本地机器上进行开发,但也意味着我们可以将测试脚本编写到远程机器上的 运行 作为构建管道的一部分。

我遇到的问题是下面文件中显示的 parser.addoption 没有得到处理。 return 似乎不是我可以使用的值(无论是默认值还是通过命令行传递的值)。

我的conftest.py文件如下(*注意url和远程IP只是为了保护公司隐私的样本)

#conftest.py

import pytest
import os
import rootdir_ref
import webdriverwrapper
from webdriverwrapper import DesiredCapabilities, FirefoxProfile



#when running tests from command line we should be able to pass --url=www..... for a different website, check what order these definitions need to be in
def pytest_addoption(parser):
    parser.addoption("--url", action="store", default="https://mydomain1.com.au")
    parser.addoption("--runenv", action="store", default="local")

@pytest.fixture(scope='session')
def url(request):
     return request.config.option.url

@pytest.fixture(scope='session')
def runenv(request):
     return request.config.option.runenv

BROWSERS = {}


if runenv == 'remote':
    BROWSERS = {'chrome_remote': DesiredCapabilities.CHROME}
else:
    BROWSERS = {'chrome': DesiredCapabilities.CHROME}



# BROWSERS = {
#     #'firefox': DesiredCapabilities.FIREFOX,
#     # 'chrome': DesiredCapabilities.CHROME,
#      'chrome_remote': DesiredCapabilities.CHROME,
#     # 'firefox_remote': DesiredCapabilities.FIREFOX
# }

@pytest.fixture(scope='function', params=BROWSERS.keys())
def browser(request):

    if request.param == 'firefox':
        firefox_capabilities = BROWSERS[request.param]
        firefox_capabilities['marionette'] = True
        firefox_capabilities['acceptInsecureCerts'] = True
        theRootDir = os.path.dirname(rootdir_ref.__file__)
        ffProfilePath = os.path.join(theRootDir, 'DriversAndTools', 'FirefoxSeleniumProfile')
        geckoDriverPath = os.path.join(theRootDir, 'DriversAndTools', 'geckodriver.exe')
        profile = FirefoxProfile(profile_directory=ffProfilePath)
       #  Testing with local Firefox Beta 56
        binary = 'C:\Program Files\Mozilla Firefox\firefox.exe'
        b = webdriverwrapper.Firefox(firefox_binary=binary, firefox_profile=profile, capabilities=firefox_capabilities,
                                     executable_path=geckoDriverPath)

    elif request.param == 'chrome':
        desired_cap = BROWSERS[request.param]
        desired_cap['chromeOptions'] = {}
        desired_cap['chromeOptions']['args'] = ['--disable-plugins', '--disable-extensions']
        desired_cap['browserName'] = 'chrome'
        desired_cap['javascriptEnabled'] = True
        theRootDir = os.path.dirname(rootdir_ref.__file__)
        chromeDriverPath = os.path.join(theRootDir, 'DriversAndTools', 'chromedriver.exe')
        b = webdriverwrapper.Chrome(chromeDriverPath, desired_capabilities=desired_cap)

    elif request.param == 'chrome_remote':
        desired_cap = BROWSERS[request.param]
        desired_cap['chromeOptions'] = {}
        desired_cap['chromeOptions']['args'] = ['--disable-plugins', '--disable-extensions']
        desired_cap['browserName'] = 'chrome'
        desired_cap['javascriptEnabled'] = True
        b = webdriverwrapper.Remote(command_executor='http://192.168.1.1:4444/wd/hub', desired_capabilities=desired_cap)

    elif request.param == 'firefox_remote':
        firefox_capabilities = BROWSERS[request.param]
        firefox_capabilities['marionette'] = True
        firefox_capabilities['acceptInsecureCerts'] = True
        firefox_capabilities['browserName'] = 'firefox'
        firefox_capabilities['javascriptEnabled'] = True
        theRootDir = os.path.dirname(rootdir_ref.__file__)
        ffProfilePath = os.path.join(theRootDir, 'DriversAndTools', 'FirefoxSeleniumProfile')
        profile = FirefoxProfile(profile_directory=ffProfilePath)
        b = webdriverwrapper.Remote(command_executor='http://192.168.1.1:4444/wd/hub',
                                    desired_capabilities=firefox_capabilities, browser_profile=profile)

    else:
        b = BROWSERS[request.param]()
    request.addfinalizer(lambda *args: b.quit())

    return b


@pytest.fixture(scope='function')
def driver(browser, url):
    driver = browser
    driver.set_window_size(1260, 1080)
    driver.get(url)
    return driver

在 conftest 设置页面后,我的测试将简单地使用生成的 "driver" fixture。示例测试可能:

import pytest
from testtools import login, dashboard, calendar_helper, csvreadtool, credentials_helper
import time

@pytest.mark.usefixtures("driver")
def test_new_appointment(driver):

    testId = 'Calendar01'
    credentials_list = credentials_helper.get_csv_data('LoginDetails.csv', testId)

    # login
    assert driver.title == 'Patient Management cloud solution'
    rslt = login.login_user(driver, credentials_list)
.... etc..

然后我想 运行 测试套件使用如下命令: python -m pytest -v --html=.\Results\testrunX.html --self-contained-html --url=https://myotherdomain.com.au/ --运行env=chrome_remote

到目前为止 url 命令行选项有效,我可以用它来覆盖 url 或让它使用默认值。

但我无法从 运行env 命令行选项中获取值。在下面的 if 语句中,它将始终默认为 else 语句。 运行env 似乎没有值,尽管我的默认 parser.addoption 是 'local'

if runenv == 'remote':
    BROWSERS = {'chrome_remote': DesiredCapabilities.CHROME}
else:
    BROWSERS = {'chrome': DesiredCapabilities.CHROME}

我尝试在 if 语句之前放入 pdb.trace() 以便我可以看到 运行env 中的内容,但它只会告诉我它是一个函数而我似乎没有能够从中获取一个值,这让我觉得它根本没有被填充。

我不太确定如何调试 conftest 文件,因为输出通常不会出现在控制台输出中。有什么建议么? pytest_addoption 是否真的接受 2 个或更多自定义命令行参数?

我正在使用 Python 3.5.3 测试 3.2.1 在 windows 10

上的 VirtualEnv 中

BROWSERSconftest.py 导入 时填充,在导入时 runenv 是一个函数。如果你想使用 runenv 作为 fixture BROWSERS 也必须是 fixture:

@pytest.fixture(scope='session')
def BROWSERS(runenv):
    if runenv == 'remote':
        return {'chrome_remote': DesiredCapabilities.CHROME}
    else:
        return {'chrome': DesiredCapabilities.CHROME}

好的,在完成概念验证之后,我的问题的主要部分似乎是我无法使用命令行选项来更改函数(固定装置或非固定装置函数)的输出,并且然后将其用作另一个请求夹具函数的动态参数列表。在阅读了它之后,它似乎与夹具功能加载期间的处理顺序有关。除了玩 metafunc 之外,我几乎尝试了所有方法。

我尝试使用所有各种 pytest.mark.fixture 或 params = 部分中的任何变体,它们根本不会产生可迭代列表(在某些情况下我可以得到它给我整个列表但不是遍历它)

我也尝试了lazyfixture模型,但没有成功。

我尝试在夹具函数中使用字典作为输出。我在函数外尝试了它们,我用 类 尝试了同样的事情,并在 fixture function 中创建了 populated objected 。我尝试在 params = 中使用 pytest.mark.getfixturevalue ,我尝试使用 pytest.mark.use 装饰器,我尝试了 paramatize 装饰器。 None 个有效。

看起来这里唯一可行的是这里提出的替代解决方案,它实际上还没有被开发出来。 https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html

最后我决定将所有逻辑都包含在一个大的 fixture 函数中,这似乎暂时有效,但不是我想要的理想方式,因为不幸的是我不能有基于命令的可变参数我要测试的浏览器的行条目。我必须手动更新 conftest 文件以确定我是否 运行 一个或 2 个浏览器,并让它在每个测试中迭代这两个浏览器。

# conftest.py

import pytest
import os
import rootdir_ref
import webdriverwrapper
from webdriverwrapper import DesiredCapabilities, FirefoxProfile


# when running tests from command line we should be able to pass --url=www..... for a different website, check what order these definitions need to be in
def pytest_addoption(parser):
    parser.addoption('--url', action='store', default='https://mytestdomain.com.au/', help='target machine url')
    parser.addoption('--runenv', action='store', default='remote', help='select remote or local')


@pytest.fixture(scope='session')
def url(request):
    return request.config.getoption('url')


@pytest.fixture(scope='session')
def runenv(request):
    return request.config.getoption('runenv')

BROWSERS = {
    # 'firefox': DesiredCapabilities.FIREFOX,
    'chrome': DesiredCapabilities.CHROME
}

@pytest.fixture(scope='function', params=BROWSERS.keys())
def browser(request, runenv):
    if request.param == 'firefox':

        if runenv == 'local':
            firefox_capabilities = BROWSERS[request.param]
            firefox_capabilities['marionette'] = True
            firefox_capabilities['acceptInsecureCerts'] = True
            theRootDir = os.path.dirname(rootdir_ref.__file__)
            ffProfilePath = os.path.join(theRootDir, 'DriversAndTools', 'FirefoxSeleniumProfile')
            geckoDriverPath = os.path.join(theRootDir, 'DriversAndTools', 'geckodriver.exe')
            profile = FirefoxProfile(profile_directory=ffProfilePath)
            #  Testing with local Firefox Beta 56
            binary = 'C:\Program Files\Mozilla Firefox\firefox.exe'
            b = webdriverwrapper.Firefox(firefox_binary=binary, firefox_profile=profile, capabilities=firefox_capabilities,
                                         executable_path=geckoDriverPath)
        elif runenv == 'remote':
            request.param == 'firefox_remote'
            firefox_capabilities = BROWSERS[request.param]
            firefox_capabilities['marionette'] = True
            firefox_capabilities['acceptInsecureCerts'] = True
            firefox_capabilities['browserName'] = 'firefox'
            firefox_capabilities['javascriptEnabled'] = True
            theRootDir = os.path.dirname(rootdir_ref.__file__)
            ffProfilePath = os.path.join(theRootDir, 'DriversAndTools', 'FirefoxSeleniumProfile')
            profile = FirefoxProfile(profile_directory=ffProfilePath)
            b = webdriverwrapper.Remote(command_executor='https://selenium.mytestserver.com.au/wd/hub',
                                        desired_capabilities=firefox_capabilities, browser_profile=profile)
        else:
            b = webdriverwrapper.Firefox()
    elif request.param == 'chrome':
        if runenv == 'local':
            desired_cap = BROWSERS[request.param]
            desired_cap['chromeOptions'] = {}
            desired_cap['chromeOptions']['args'] = ['--disable-plugins', '--disable-extensions']
            desired_cap['browserName'] = 'chrome'
            desired_cap['javascriptEnabled'] = True
            theRootDir = os.path.dirname(rootdir_ref.__file__)
            chromeDriverPath = os.path.join(theRootDir, 'DriversAndTools', 'chromedriver.exe')
            b = webdriverwrapper.Chrome(chromeDriverPath, desired_capabilities=desired_cap)
        elif runenv == 'remote':
            desired_cap = BROWSERS[request.param]
            desired_cap['chromeOptions'] = {}
            desired_cap['chromeOptions']['args'] = ['--disable-plugins', '--disable-extensions']
            desired_cap['browserName'] = 'chrome'
            desired_cap['javascriptEnabled'] = True
            b = webdriverwrapper.Remote(command_executor='https://selenium.mytestserver.com.au/wd/hub',
                                        desired_capabilities=desired_cap)
        else:
            b = webdriverwrapper.Chrome()
    else:
        b = webdriverwrapper.Chrome()
    request.addfinalizer(lambda *args: b.quit())

    return b


@pytest.fixture(scope='function')
def driver(browser, url):
    driver = browser
    driver.set_window_size(1260, 1080)
    driver.get(url)
    return driver

这里,为什么要将 urlrunenv 作为 fixture?您可以像下面这样使用它:

在你的conftest.py

def pytest_addoption(parser):
    parser.addoption('--url', action='store', default='https://mytestdomain.com.au/', help='target machine url')
    parser.addoption('--runenv', action='store', default='remote', help='select remote or local')

def pytest_configure(config):
        os.environ["url"] = config.getoption('url') 
        os.environ["runenv"] = config.getoption('runenv') 

现在,无论您想访问 urlrunenv,您只需要编写 os.getenv('Variable_name'),例如

@pytest.fixture(scope='function')
def driver(browser):
    driver = browser
    driver.set_window_size(1260, 1080)
    driver.get(os.getenv('url'))
    return driver

或者像您的代码一样,

if os.getenv('runenv')== 'remote':
    BROWSERS = {'chrome_remote': DesiredCapabilities.CHROME}
else:
    BROWSERS = {'chrome': DesiredCapabilities.CHROME}

这里,url和runenv会保存在OS环境变量中,你可以通过os.getenv()

在没有fixture的任何地方访问它

希望对您有所帮助!!