Python & Unittest 打开第二个浏览器,在第一个测试完成后测试失败
Python & Unittest open second browser, after first test have completed and test fails
找到很多关于这个问题的主题,但没有找到任何描述简单的问题解决方法,所以用这个问题创建新主题,也许会得到更好的答案。
我已经为 LoginTest 创建了测试用例,为 LegalPersonSearchTest 创建了测试用例。这两个测试用例都在单独的文件中 login.py 和 legalPersonSearch.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 - LoginTest
和 LegalPersonSearchTest
。当你 运行 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_
方法之前。
如果您对此有任何疑问,请告诉我——需要解释的内容很多,但是一旦您了解了这种架构,您就会拥有一种组织和执行测试用例的非常强大的方法。
找到很多关于这个问题的主题,但没有找到任何描述简单的问题解决方法,所以用这个问题创建新主题,也许会得到更好的答案。
我已经为 LoginTest 创建了测试用例,为 LegalPersonSearchTest 创建了测试用例。这两个测试用例都在单独的文件中 login.py 和 legalPersonSearch.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 - LoginTest
和 LegalPersonSearchTest
。当你 运行 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_
方法之前。
如果您对此有任何疑问,请告诉我——需要解释的内容很多,但是一旦您了解了这种架构,您就会拥有一种组织和执行测试用例的非常强大的方法。