Teardown method from add_finalizer of PyTest fixture doesn't work

huangapple go评论77阅读模式
英文:

Teardown method from add_finalizer of PyTest fixture doesn't work

问题

I'm trying to make a fixture for cross-browser tests with PyTest. From @pytest.mark.parametrize, the fixture receives "browser_name" and sets up the correct webdriver in an internal method. At the end of the tests, I tried to add a teardown method to close the browser, but I noticed that it just doesn't work. Can anyone help?

In my conftest.py file, I have:

import pytest
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.edge.service import Service as EdgeService
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium import webdriver

@pytest.fixture()
def WebDriverFixture(request):
    def driverSetup(browser_name):
        print("\nStarting browser...\n")
        
        match browser_name:
            case "chrome":
                options = webdriver.ChromeOptions()
                options.add_argument('excludeSwitches')
                options.add_argument('--ignore-ssl-errors=yes')
                options.add_argument('--ignore-certificate-errors')
                options.add_experimental_option("excludeSwitches", ["enable-logging"])
                driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)
                driver.implicitly_wait(10)
                return driver
                
            case "firefox":
                options = webdriver.FirefoxOptions()
                options.add_argument('excludeSwitches')
                options.add_argument('--ignore-ssl-errors=yes')
                options.add_argument('--ignore-certificate-errors')
                options.set_preference("excludeSwitches", "enable-logging")
                options.set_preference("dom.disable_beforeunload", True)
                driver = webdriver.Firefox(service=FirefoxService(GeckoDriverManager().install()), options=options)
                driver.implicitly_wait(10)
                return driver
                
            case "edge":
                options = webdriver.EdgeOptions()
                options.add_argument('excludeSwitches')
                options.add_argument('--ignore-ssl-errors=yes')
                options.add_argument('--ignore-certificate-errors')
                options.accept_insecure_certs = True
                driver = webdriver.Edge(service=EdgeService(EdgeChromiumDriverManager().install()), options=options)
                driver.implicitly_wait(10)
                return driver

        def teardown(driverSetup):
            driver = driverSetup(browser_name)
            print("\nQuitting browser...")
            driver.quit()
        request.add_finalizer(teardown(driverSetup))  
        
    return driverSetup

In the test file, I have:

import pytest
from pages.login_page import LoginPage
from pages.base_page import BasePage
import time

@pytest.mark.parametrize('browser_name', ['chrome'])
def test_negative_cases(WebDriverFixture, browser_name):
    driver = WebDriverFixture(browser_name)
    # tests
    ...
英文:

I'm trying to make a fixture for cross-browser tests with PyTest. From @pytest.mark.parametrize fixture gets "browser_name" and sets up correct webdriver in internal method. In the end of tests I tried to add a teardowm method to close browser, but I noticed that it just doesn't work. Can anyone help?

In my conftest.py file I have:

import pytest
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.firefox.service import Service as FirefoxService
from selenium.webdriver.edge.service import Service as EdgeService
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.microsoft import EdgeChromiumDriverManager
from selenium import webdriver
@pytest.fixture()
def WebDriverFixture(request):
def driverSetup(browser_name):
print("\nStarting browser...\n")
match browser_name:
case "chrome":
options = webdriver.ChromeOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.add_experimental_option("excludeSwitches", ["enable-logging"])
driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
case "firefox":
options = webdriver.FirefoxOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.set_preference("excludeSwitches", "enable-logging")
options.set_preference("dom.disable_beforeunload", True)
driver = webdriver.Firefox(service=FirefoxService(GeckoDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
case "edge":
options = webdriver.EdgeOptions()
options.add_argument('excludeSwitches')
options.add_argument('--ignore-ssl-errors=yes')
options.add_argument('--ignore-certificate-errors')
options.accept_insecure_certs = True
driver = webdriver.Edge(service=EdgeService(EdgeChromiumDriverManager().install()), options=options)
driver.implicitly_wait(10)
return driver
def teardown(driverSetup):
driver = driverSetup(browser_name)
print("\nQuitting browser...")
driver.quit()
request.add_finalizer(teardown(driverSetup))  
return driverSetup

In test file I have:

import pytest
from pages.login_page import LoginPage
from pages.base_page import BasePage
import time
@pytest.mark.parametrize('browser_name', ['chrome'])
def test_negative_cases(WebDriverFixture, browser_name):
driver = WebDriverFixture(browser_name)
#tests
...

答案1

得分: 1

使用yield对于您的情况比使用return更好,因为您希望在最后执行另一个操作(关闭浏览器)。

我已经修改了代码(如下所示),以显示一个最小工作示例,可以处理pytest参数化并在最后关闭浏览器。

from selenium import webdriver
import pytest
import time

@pytest.fixture
def WebDriverFixture(request):
    driver = None
    browser_name = request.getfixturevalue("browser_name")
    if browser_name.lower() == "chrome":
        driver = webdriver.Chrome()
    elif browser_name.lower() == "firefox":
        driver = webdriver.Firefox()
    elif browser_name.lower() == "edge":
        driver = webdriver.Edge()
    else:
        raise Exception("未知浏览器")
    yield driver
    try:
        driver.quit()
    except Exception:
        pass

@pytest.mark.parametrize('browser_name', ['chrome', 'firefox', 'edge'])
def test_negative_cases(WebDriverFixture, browser_name):
   driver = WebDriverFixture
   driver.get("https://example.com")
   time.sleep(1)

最新版本的selenium已经包含了webdriver_manager,因此您不再需要单独添加它。

英文:

Using yield is a better option than using return for your scenario, because you want to go back and perform another action at the end (closing the browser).

I've modified the code (see below) to show a minimally working example that handles the pytest parameterization and closes browsers at the end.

from selenium import webdriver
import pytest
import time

@pytest.fixture
def WebDriverFixture(request):
    driver = None
    browser_name = request.getfixturevalue("browser_name")
    if browser_name.lower() == "chrome":
        driver = webdriver.Chrome()
    elif browser_name.lower() == "firefox":
        driver = webdriver.Firefox()
    elif browser_name.lower() == "edge":
        driver = webdriver.Edge()
    else:
        raise Exception("Unknown browser")
    yield driver
    try:
        driver.quit()
    except Exception:
        pass

@pytest.mark.parametrize('browser_name', ['chrome', 'firefox', 'edge'])
def test_negative_cases(WebDriverFixture, browser_name):
   driver = WebDriverFixture
   driver.get("https://example.com")
   time.sleep(1)

The latest version of selenium already includes webdriver_manager now, so you no longer need to add that separately.

huangapple
  • 本文由 发表于 2023年6月29日 22:02:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581784.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定