2017-09-07 8 views
0

J'ai un fichier conftest pour gérer la configuration et le démontage des pilotes de sélénium lors de l'exécution de tests dans pytest. J'essaye d'ajouter dans une option de ligne de commande pour déterminer si j'exécute le local a sélénium intégré et les conducteurs de Web ou un serveur de sélenium à distance et des conducteurs etc ...Comment accéder à l'entrée de la ligne de commande dans pytest conftest à partir de pytest_addoptions et l'utiliser dans les paramètres de fixture?

J'ai ajouté une option commandline appelée "runenv" et j'essaye d'obtenir la valeur de chaîne de ceci entrée par la ligne de commande pour déterminer si le système devrait exécuter la configuration de webdriver locale ou distante. Cela permet aux testeurs de développer localement leurs propres machines, mais cela signifie également que nous pouvons programmer les tests pour qu'ils s'exécutent sur la machine distante dans le cadre d'un pipeline de build.

Le problème que j'ai, c'est que mon parser.addoption montré dans le fichier ci-dessous n'est pas traité. Il ne semble pas renvoyer une valeur (que ce soit la valeur par défaut ou la valeur transmise par la ligne de commande) que je peux utiliser.

Mon fichier conftest.py est la suivante (* Notez l'URL et IP à distance ne sont que des échantillons pour couvrir la vie privée de l'entreprise)

#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 

Mes tests serait tout simplement utiliser le résultat de projecteur « pilote » Une fois la page déjà été installé par conftest. test Exemple peut-être:

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

J'aimerais ensuite lancer la suite de test à l'aide d'une commande comme:. python -m pytest -v --html = \ Résultats \ testrunX.html --self-contained- html --url = https://myotherdomain.com.au/ --runenv = chrome_remote

Jusqu'à présent, l'option de ligne de commande url fonctionne, je peux l'utiliser pour remplacer l'URL ou la laisser utiliser la valeur par défaut.

Mais je ne peux pas obtenir une valeur de l'option de ligne de commande runenv. Dans l'instruction if ci-dessous, elle sera toujours par défaut à l'instruction else. runenv ne semble pas avoir une valeur, même si la valeur par défaut que j'ai pour que parser.addoption est « local »

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

J'ai essayé de mettre en pdb.trace() avant l'instruction if que je puisse voir ce que est dans le runenv, mais il me dira seulement que c'est une fonction et je ne semble pas pouvoir en obtenir une valeur, ce qui me fait penser que ça ne se remplit pas du tout.

Je ne suis pas vraiment sûr comment déboguer le fichier conftest parce que la sortie n'apparaît généralement pas dans la sortie de la console. Aucune suggestion? Est-ce que pytest_addoption accepte réellement 2 arguments de ligne de commande personnalisés ou plus?

J'utilise Python 3.5.3 Pytest 3.2.1 Dans un virtualenv sur les fenêtres 10

Répondre

1

Voici, pourquoi faites-vous url et runenv comme appareil? Vous pouvez l'utiliser comme ci-dessous:

Dans votre 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') 

Maintenant, chaque fois que vous voulez accéder url et runenv vous avez juste besoin d'écrire comme 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 

Ou comme dans votre code,

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

Ici, url et r unenv serait enregistré dans la variable d'environnement OS et vous pouvez y accéder n'importe où sans fixture juste par os.getenv()

Espérons que cela vous aiderait !!

+0

Merci @Chanda c'est génial !. Merci beaucoup. Je vais essayer dès que j'ai une chance. – Roochiedoor

+0

Cette réponse était exactement ce dont j'avais besoin. Merci beaucoup. – Roochiedoor

1

BROWSERS sont peuplés à conftest.pyimportation et au moment de l'importation runenv est une fonction. Si vous souhaitez utiliser runenv comme un appareil BROWSERS doit également être un élément:

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

Merci @phd, j'ai essayé de faire BROWSERS dans une fonction de fixture, mais j'ai eu des problèmes avec la fonction du navigateur qui utilise les paramètres: '@ pytest.fixture (scope = 'function', params = BROWSERS.keys()) 'Suivi par' def browser (request): 'J'ai appris depuis que je ne peux pas utiliser la sortie d'un appareil décoré dans le fichier dans lequel il est déclaré parce que le nom fait référence à la déclaration de la fonction. Selon la documentation ici, je pense que je devrais être en mesure d'utiliser le "Nom" dans la définition de l'appareil https://docs.pytest.org/en/latest/builtin.html#fixtures-and-requests mais ne peut pas tout à fait travailler il dehors – Roochiedoor

0

Bon alors après avoir fait une preuve de concept, il ressemble à la partie principale de mon problème est que je ne peux pas utiliser une ligne de commande option pour changer la sortie d'une fonction (soit une fonction fixture ou non fixture) et ensuite l'utiliser comme une liste pour un paramètre dynamique sur une autre fonction de fixation de demande.Après avoir lu à ce sujet, il semblerait que cela a quelque chose à voir avec l'ordre de traitement pendant le chargement des fonctions de l'appareil. J'ai presque tout essayé en dehors de jouer avec le metafunc.

J'ai essayé d'utiliser tous les différents pytest.mark.fixture ou toutes les variations dans la section params = et ils ne donneraient tout simplement pas une liste itérative (à certaines occasions je pourrais l'obtenir pour me donner la liste entière mais pas itérer over it)

J'ai également essayé le modèle lazyfixture sans succès.

J'ai essayé d'utiliser des dictionnaires dans la fonction d'un appareil comme sortie. Je les ai essayés en dehors de la fonction, j'ai essayé la même chose avec des classes et en créant des objets peuplés dans une fonction de montage. J'ai essayé d'utiliser le pytest.mark.getfixturevalue dans les paramètres =, j'ai essayé d'utiliser le décorateur pytest.mark.use, j'ai essayé le décorateur paramatize. Rien de tout cela ne fonctionne.

Il semble que la seule chose qui pourrait fonctionner ici serait la solution alternative proposée ici, qui n'a pas été développée. https://docs.pytest.org/en/latest/proposals/parametrize_with_fixtures.html

En fin de compte j'ai décidé de contenir toute la logique d'une grande fonction de fixation, qui semble fonctionner pour un moment, mais pas idéalement comment je voudrais le faire parce que, malheureusement, je ne peux pas avoir params variables en fonction entrées de ligne de commande pour quels navigateurs je veux tester. Je dois mettre à jour manuellement le fichier conftest au hasard si je n'exécute pas un ou deux navigateurs et l'ai itéré par les deux pour chaque essai.

# 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