英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论