考虑下面的示例,由于我在
setUp
方法中初始化驱动程序并在 test_login
中使用它,浏览器将打开两次,第一次在 setUp
期间,然后它将关闭并开始测试.
如果我从
setUp
中删除逻辑并将其放入test_login
中,则驱动程序将在test_profile
和tearDown
中未定义
初始化驱动程序并在整个课程中使用它而不导致浏览器打开两次的正确方法是什么?
from selenium import webdriver
import unittest
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
class Test(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()))
self.driver.get('https://example.com/login')
self.current_url = self.driver.current_url
self.dashboard_url = 'https://example.com/dashboard'
def test_login(self):
self.assertEqual(self.dashboard_url, self.current_url)
def test_profile(self):
self.driver.get('https://example.com/profile')
def tearDown(self):
self.driver.close()
您需要使用 setUpClass / tearDownClass:
import unittest
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print('setUpClass')
@classmethod
def tearDownClass(cls) -> None:
print('tearDownClass')
def setUp(self):
print('setUp')
def test_login(self):
print('login')
def test_profile(self):
print('profile')
def tearDown(self):
print('tearDown')
你的代码运行得很好。请在setUp和tearDown方法之前添加装饰器
@classmethod
。
另外,问题在于 setUp 方法中的 self.driver.get('https://example.com/login')
行。只需从那里删除它,也许创建一个新函数来保存该代码。
这是一个将
unittest.TestCase
与 Selenium 结合使用的示例。它具有 setUp()
和 tearDown()
步骤,并且它会获得您正在寻找的所需行为,尽管可能比您要求的更多。
您可以使用
python -m unittest
运行它:
import sys
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from unittest import TestCase
class RefinedRawSelenium(TestCase):
def setUp(self):
self.driver = None
options = webdriver.ChromeOptions()
options.add_argument("--disable-notifications")
if "linux" in sys.platform:
options.add_argument("--headless=new")
options.add_experimental_option(
"excludeSwitches", ["enable-automation", "enable-logging"],
)
prefs = {
"credentials_enable_service": False,
"profile.password_manager_enabled": False,
}
options.add_experimental_option("prefs", prefs)
self.driver = webdriver.Chrome(options=options)
def tearDown(self):
if self.driver:
try:
if self.driver.service.process:
self.driver.quit()
except Exception:
pass
def wait_for_element_visible(
self, selector, by="css selector", timeout=10
):
try:
return WebDriverWait(self.driver, timeout).until(
EC.visibility_of_element_located((by, selector))
)
except Exception:
raise Exception(
"Element {%s} was not visible after %s seconds!"
% (selector, timeout)
)
def wait_for_element_clickable(
self, selector, by="css selector", timeout=10
):
try:
return WebDriverWait(self.driver, timeout).until(
EC.element_to_be_clickable((by, selector))
)
except Exception:
raise Exception(
"Element {%s} was not visible/clickable after %s seconds!"
% (selector, timeout)
)
def wait_for_element_not_visible(
self, selector, by="css selector", timeout=10
):
try:
return WebDriverWait(self.driver, timeout).until(
EC.invisibility_of_element((by, selector))
)
except Exception:
raise Exception(
"Element {%s} was still visible after %s seconds!"
% (selector, timeout)
)
def open(self, url):
self.driver.get(url)
def click(self, selector, by="css selector", timeout=7):
el = self.wait_for_element_clickable(selector, by=by, timeout=timeout)
el.click()
def type(self, selector, text, by="css selector", timeout=10):
el = self.wait_for_element_clickable(selector, by=by, timeout=timeout)
el.clear()
if not text.endswith("\n"):
el.send_keys(text)
else:
el.send_keys(text[:-1])
el.submit()
def assert_element(self, selector, by="css selector", timeout=7):
self.wait_for_element_visible(selector, by=by, timeout=timeout)
def assert_text(self, text, selector="html", by="css selector", timeout=7):
el = self.wait_for_element_visible(selector, by=by, timeout=timeout)
self.assertIn(text, el.text)
def assert_exact_text(self, text, selector, by="css selector", timeout=7):
el = self.wait_for_element_visible(selector, by=by, timeout=timeout)
self.assertEqual(text, el.text)
def assert_element_not_visible(
self, selector, by="css selector", timeout=7
):
self.wait_for_element_not_visible(selector, by=by, timeout=timeout)
def test_add_item_to_cart(self):
self.open("https://www.saucedemo.com")
self.type("#user-name", "standard_user")
self.type("#password", "secret_sauce\n")
self.assert_element("div.inventory_list")
self.assert_text("PRODUCTS", "span.title")
self.click('button[name*="backpack"]')
self.click("#shopping_cart_container a")
self.assert_exact_text("YOUR CART", "span.title")
self.assert_text("Backpack", "div.cart_item")
self.click("#remove-sauce-labs-backpack")
self.assert_element_not_visible("div.cart_item")
self.click("#react-burger-menu-btn")
self.click("a#logout_sidebar_link")
self.assert_element("input#login-button")
# When run with "python" instead of "pytest" or "python -m unittest"
if __name__ == "__main__":
from unittest import main
main()
这是取自我在 SeleniumBase/examples/migration/raw_selenium/refined_raw.py
中的示例这实际上将是我今年在 SeleniumConf 2023 会议上的一部分(https://seleniumconf.com/agenda/#python-selenium-fundamentals-to-frameworks-with-seleniumbase),我将在那里进行演示如何将其简化为这样的内容,在导入中在幕后使用
unittest.TestCase
:
from seleniumbase import BaseCase
class CleanSeleniumBase(BaseCase):
def test_add_item_to_cart(self):
self.open("https://www.saucedemo.com")
self.type("#user-name", "standard_user")
self.type("#password", "secret_sauce\n")
self.assert_element("div.inventory_list")
self.assert_text("PRODUCTS", "span.title")
self.click('button[name*="backpack"]')
self.click("#shopping_cart_container a")
self.assert_exact_text("YOUR CART", "span.title")
self.assert_text("Backpack", "div.cart_item")
self.click("#remove-sauce-labs-backpack")
self.assert_element_not_visible("div.cart_item")
self.click("#react-burger-menu-btn")
self.click("a#logout_sidebar_link")
self.assert_element("input#login-button")
# When run with "python" instead of "pytest"
if __name__ == "__main__":
from pytest import main
main([__file__, "-s"])
(那个使用
seleniumbase.BaseCase
,它继承了unittest.TestCase
。示例来自SeleniumBase/examples/migration/raw_selenium/simple_sbase.py)