【问题标题】:Python Unittest: How to initialize selenium in a class and avoid having the browser opening twice?Python Unittest:如何在类中初始化 selenium 并避免浏览器打开两次?
【发布时间】:2023-01-20 23:51:11
【问题描述】:

考虑下面的示例,因为我在 setUp 方法中初始化驱动程序并在 test_login 中使用它,浏览器将打开两次,第一次在 setUp 期间打开,然后它将关闭并开始测试。

如果我从setUp 中删除逻辑并将其放入test_login,则驱动程序将在test_profiletearDown 中未定义

在不导致浏览器打开两次的情况下,初始化驱动程序并在整个课程中使用它的正确方法是什么?

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

【问题讨论】:

    标签: python selenium python-unittest


    【解决方案1】:

    您需要使用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')
    

    【讨论】:

      【解决方案2】:

      您的代码工作正常。请在 setUp 和 tearDown 方法之前添加装饰器@classmethod。 此外,setUp 方法中的行 self.driver.get('https://example.com/login') 也存在问题。只需从那里删除它,然后创建一个新函数来保存该代码。

      【讨论】:

        【解决方案3】:

        这是一个将 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("
        "):
                    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
        ")
                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
        ")
                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

        【讨论】:

        • 虽然它是一个很好的例子,但并没有真正回答所提出的问题。您在无头模式下使用 chrome,而问题是浏览器不应打开两次,而应打开一次。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-05-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-06
        • 2018-03-01
        相关资源
        最近更新 更多