简体   繁体   English

如何从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?

I have a conftest file to handle the setup and tear down of selenium drivers when running tests in pytest. 我有一个conftest文件,用于在pytest中运行测试时处理硒驱动程序的设置和拆除。 I'm trying to add in a command line option to determine if I run the local built in selenium and web drivers or a remote selenium server and drivers etc... 我正在尝试添加命令行选项以确定我是否运行本地内置的selenium和Web驱动程序或远程selenium服务器和驱动程序等...

I've added a commandline option called "runenv" and I'm trying to obtain the string value from this entered through command line to determine if the system should run local or remote webdriver configuration. 我添加了一个名为“ runenv”的命令行选项,并且试图从通过命令行输入的字符串值中获取字符串值,以确定系统是否应运行本地或远程Webdriver配置。 This allows testers to develop on their own machines locally, but also means we can script the tests to run on the remote machine as part of a build pipeline. 这使测试人员可以在自己的本地计算机上进行开发,但也意味着我们可以编写测试脚本,以将其作为构建管道的一部分在远程计算机上运行。

The issue I have is that my parser.addoption shown in the below file is not processed. 我的问题是以下文件中显示的parser.addoption未得到处理。 It doesn't seem return a value (whether it's the default or the value passed through command line) that I can use. 似乎没有返回我可以使用的值(无论是默认值还是通过命令行传递的值)。

My conftest.py file is as follows (*note the url and remote IP are just samples to cover company privacy) 我的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

My tests would simply utilise the resulting "driver" fixture after the page has already been setup by conftest. 在conftest设置页面之后,我的测试将仅利用生成的“驱动程序”固定装置。 Example test maybe: 测试示例可能是:

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..

I'd then like to run the test suite using a command like: python -m pytest -v --html=.\\Results\\testrunX.html --self-contained-html --url= https://myotherdomain.com.au/ --runenv=chrome_remote 然后,我想使用以下命令运行测试套件:python -m pytest -v --html =。\\ Results \\ testrunX.html --self-contained-html --url = https://myotherdomain.com .au / --runenv = chrome_remote

So far the url command line option works, I can use it to override the url or let it use the default. 到目前为止,url命令行选项有效,我可以使用它来覆盖url或使用默认值。

But I can not get a value from the runenv commandline option. 但是我无法从runenv命令行选项获取值。 In the if statement below it will always default to the else statement. 在下面的if语句中,它将始终默认为else语句。 runenv doesn't seem to have a value, even though the default I have for that parser.addoption is 'local' 即使我对该parser.addoption的默认设置为'local',runenv似乎也没有值。

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

I tried putting in pdb.trace() before the if statement so I could see what is in the runenv, but it will only tell me it's a function and I don't seem to be able to obtain a value from it, which makes me think it's not getting populated at all. 我尝试在if语句之前放入pdb.trace(),以便可以看到runenv中的内容,但是它只会告诉我这是一个函数,而且我似乎无法从中获取值,这使得我认为这里根本没有人烟。

I'm not really sure how to debug the conftest file because the output generally does not appear in the console output. 我不确定如何调试conftest文件,因为输出通常不会出现在控制台输出中。 Any suggestions? 有什么建议么? Does the pytest_addoption actually accept 2 or more custom command line arguments? pytest_addoption实际上接受2个或更多自定义命令行参数吗?

I'm using Python 3.5.3 Pytest 3.2.1 In a VirtualEnv on windows 10 我在Windows 10的VirtualEnv中使用Python 3.5.3 Pytest 3.2.1

Here, why are you making url and runenv as fixture? 在这里,为什么要使用urlrunenv作为灯具? You can use it like below: 您可以如下使用它:

In your conftest.py 在你的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') 

Now, wherever you want to access url and runenv you just need to write os.getenv('Variable_name') like, 现在,无论您要访问urlrunenv哪里, runenv需要编写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

Or like in your code, 或者像您的代码中一样

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

Here, url and runenv would be saved in OS environment variable and you can access it anywhere without fixture just by os.getenv() 在这里,url和runenv将保存在OS环境变量中,并且您可以仅通过os.getenv()就可以在没有固定装置的情况下访问它

Hope it would help you !! 希望对你有帮助!

BROWSERS are populated at conftest.py import and at import time runenv is a function. BROWSERS器在conftest.py 导入时填充,而在导入时runenv是一个函数。 If you want to use runenv as a fixture BROWSERS also must be a fixture: 如果要将runenv用作固定装置, BROWSERS也必须是固定装置:

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

Okay so after doing a proof of concept it looks like the main part of my problem is that I can't use a command line option to change the output of a function (either a fixture or non fixture function) and then use that as a list for a dynamic paramater on another request fixture function. 好的,在做完概念验证之后,看来我问题的主要部分是我无法使用命令行选项来更改函数(夹具或非夹具函数)的输出,然后将其用作另一个请求夹具功能上的动态参数列表。 After reading up about it, it would seem that it's something to do with the order of processing during loading of the fixture functions. 在阅读了有关它的内容之后,似乎与加载夹具功能期间的处理顺序有关。 I pretty much tried everything apart from playing with the metafunc . 除了玩metafunc之外,我几乎尝试了所有其他方法。

I tried using all of the various pytest.mark.fixture or any variations in the params = section and they would simply not yield an iterable list (on some occasions I could get it to give me the entire list but not iterate over it) 我尝试使用所有各种pytest.mark.fixture或params =部分中的任何变体,它们根本不会产生可迭代的列表(在某些情况下,我可以将其提供给我整个列表,但不会对其进行迭代)

I also tried the lazyfixture model with no success. 我也尝试过lazyfixture模型,但没有成功。

I tried using dictionaries in the a fixture function as the out put. 我尝试在夹具功能中使用字典作为输出。 I tried them outside the function, I tried the same thing with classes and creating populated objected inside a fixture function . 我在函数外尝试了它们,我对类进行了同样的尝试,并在夹具函数内创建了填充对象。 I tried using the pytest.mark.getfixturevalue in the params = , I tried using the pytest.mark.use decorator, I tried the paramatize decorator. 我尝试在params =中使用pytest.mark.getfixturevalue,尝试使用pytest.mark.use装饰器,尝试了参数化装饰器。 None of of it works. 这些都不起作用。

It looks like the only thing that may work here would be the alternative proposed solution here, that has not actually been developed. 似乎唯一可行的方法是在此处提出尚未实际开发的替代解决方案。 https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html

In the end I decided to contain all of the logic one large fixture function, which seems to work for moment, but not ideally how I'd like to do it because unfortunately I can not have variable params based on command line entries for which browsers I want to test. 最后,我决定将所有逻辑都包含在一个大型Fixture函数中,该函数似乎可以暂时使用,但并不是理想的方式,因为不幸的是,我无法基于浏览器的命令行条目获得可变参数我要测试。 I have to manually update the conftest file to chance whether I not I run one or 2 browsers and have it iterate through both for each test. 我必须手动更新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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM