Python & Unittest 打开第二个浏览器,在第一个测试完成后测试失败

Python & Unittest open second browser, after first test have completed and test fails

找到很多关于这个问题的主题,但没有找到任何描述简单的问题解决方法,所以用这个问题创建新主题,也许会得到更好的答案。

我已经为 LoginTest 创建了测试用例,为 LegalPersonSearchTest 创建了测试用例。这两个测试用例都在单独的文件中 login.pylegalPersonSearch.py

from utils.utils import *
from selenium import webdriver
from locators.locators import Locators
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import unittest
from pages.loginPage import LoginPage


class LoginTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
    cls.driver = webdriver.Firefox()
    cls.driver.implicitly_wait(10)
    cls.driver.maximize_window()
    cls.driver.get(URL)

def test_valid_login(self):
    driver = self.driver

    login = LoginPage(driver)
    login.fill_login_form(adminUsername, adminPassword)
    login.click_login_button()


if __name__ == '__main__':
    unittest.main()

我认为新浏览器在测试之间打开的原因是在第二个文件中声明 驱动程序

from selenium import webdriver
import unittest
from pages.legalPersonSearchPage import LegalPersonSearchPage

class LegalPersonSearchTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
    cls.driver = webdriver.Firefox()

def test_valid_organization_search(self):
    driver = self.driver
    legal = LegalPersonSearchPage(driver)

    legal.open_legal_person_search_page()

@classmethod
def tearDown(cls):
    cls.driver.quit()


if __name__ == '__main__':
    unittest.main()

如何修改 LoginTest 浏览器只打开一次,而不是在测试之间?

我需要修改它,因为登录后(这是测试的 1/2)是测试的第二部分。它将完成,然后浏览器关闭并打开新的并重新开始登录。

正如有人告诉我的那样,最佳做法是将登录测试部分排除在整个测试之外。

回答您的一个问题 -- driver 被打开两次,因为您有两种不同的 setUp() 方法,一种用于您的 classes - LoginTestLegalPersonSearchTest。当你 运行 test_valid_login 时,你的 setUpClass() 方法被调用,它初始化 driver。然后,测试 运行s。此 driver 实例永远不会被拆除,因此 window 保持打开状态。

然后,test_valid_organization_search运行秒。这个 class 也有它自己的 setUpClass() 方法,它初始化另一个 driver 实例。所以现在你有两个驱动程序,它们都在每个 class 文件的 setUpClass() 方法中打开。

此设置产生了您不希望的结果。我认为您有点误解了“最佳做法是将登录测试部分排除在整个测试之外”的含义。

这并不意味着您需要编写两个单独的 测试——一个用于登录,一个用于测试其余功能。这实际上是 bad practice,因为您希望您的测试用例 运行 彼此独立——测试用例不应依赖于先前的测试用例才能正确执行。

我认为您在这里寻找的解决方案是将登录功能写入您的 setUp() 方法,以便始终在测试用例开始之前执行登录。

这种方法将阻止您在测试中使用登录部分——这是您在此处提到的最初目标。

您可以通过删除重复的 setUp() 方法来调整您的 classes,并将 LoginTest 继承到您的 LegalPersonSearchTest 中,这样您只需设置一次:

from utils.utils import *
from selenium import webdriver
from locators.locators import Locators
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import unittest
from pages.loginPage import LoginPage

# this is our "base" class
class LoginTest(unittest.TestCase):

driver = None # driver instance that we will inherit into LegalPersonSearchTest

# initialize driver, go to testing URL, etc.
def setUp(cls):
    cls.driver = webdriver.Firefox()
    cls.driver.implicitly_wait(10)
    cls.driver.maximize_window()
    cls.driver.get(URL)

    # call login here to login before test
    login_page = LoginPage(cls.driver)
    login_page .fill_login_form(adminUsername, adminPassword)
    login_page .click_login_button()

# move teardown into same class as setUp()
def tearDown(cls):
    cls.driver.quit()

我们已经为 driver 声明了一个 class 变量,您可以将其传递给 LegalPersonSearchTest。我们还删除了 __main__ 调用,因为我们唯一需要的入口点是 LegalPersonSearchTest:

中的 test_ 方法
from selenium import webdriver
import unittest
from pages.legalPersonSearchPage import LegalPersonSearchPage
from login_test import LoginTest # unsure of file name containing LoginTest class

class LegalPersonSearchTest(LoginTest): # inherit LoginTest here so we can use driver


def test_valid_organization_search(self):

    legal_page = LegalPersonSearchPage(self.driver)
    legal_page .open_legal_person_search_page()


if __name__ == '__main__':
    unittest.main()

我们在这里做了一些改动:

  • __main__ 指定的主要方法的入口点 -- 我们只需要在一个地方,在测试用例级别 (LegalPersonSearchTest)
  • 删除了导致创建多个驱动程序实例的重复 setUp() 方法调用(在您的问题描述中提到)
  • LoginTest class 中创建了驱动程序的单个 class 实例以传递到 LegalPersonSearchTest class
  • 修改了 LoginTest 上的 setUp() 方法以初始化驱动程序和登录 -- 这样您就不必为任何测试包含登录代码!

更新:根据评论进行了更改:

  • LoginTest class 中删除了 login 方法并将登录代码移至 setUp() 下——这将在每个测试用例之前执行
  • 修改 test_valid_organization_search 以在初始化 PageObject
  • 时使用 self.driver 而不是 driver

我已经根据我推送到我的 GitHub 的 this sample Python test architecture 做了很多这些更改。我用作模板的文件是 base_test_fixture.py(用于您的 LoginTest),test_web_driver.py 用于您的 LegalPersonSearchTest

您可能会注意到 base_test_fixture.py 还包含 def _testInitialize()def _testCleanup() -- 这些是您可以在 覆盖 中的方法15=] class 在 test_ 方法之前执行 额外的 步骤 运行。这里的想法是,如果您有多个包含测试用例的 .py 文件,但每个 .py 文件需要的设置略有不同,并且您需要做的不仅仅是 setUp() 方法调用。可以重写测试用例class中的testInitialize()testCleanup()方法,这些方法会在setUp()和[=之后执行 91=]在实际的test_方法之前。

如果您对此有任何疑问,请告诉我——需要解释的内容很多,但是一旦您了解了这种架构,您就会拥有一种组织和执行测试用例的非常强大的方法。