简体   繁体   中英

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

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

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

So far the url command line option works, I can use it to override the url or let it use the default.

But I can not get a value from the runenv commandline option. In the if statement below it will always default to the else statement. runenv doesn't seem to have a value, even though the default I have for that parser.addoption is 'local'

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.

I'm not really sure how to debug the conftest file because the output generally does not appear in the console output. Any suggestions? Does the pytest_addoption actually accept 2 or more custom command line arguments?

I'm using Python 3.5.3 Pytest 3.2.1 In a VirtualEnv on windows 10

Here, why are you making url and runenv as fixture? You can use it like below:

In your 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,

@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()

Hope it would help you !!

BROWSERS are populated at conftest.py import and at import time runenv is a function. If you want to use runenv as a fixture BROWSERS also must be a fixture:

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

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)

I also tried the lazyfixture model with no success.

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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