12. 原生测试框架Unittest的后置处理方法的使用
原生测试框架Unittest的后置处理方法的使用
一、测试框架结构解析
1.1 基类架构设计
class Page:"""页面对象基类"""url = Nonedriver = None@classmethoddef cls_element(cls, loc:tuple):"""类级别元素定位方法"""return cls.driver.find_element(*loc)def element(self, loc: tuple):"""实例级别元素定位"""return self.driver.find_element(*loc)
核心特征:
- 实现双模式定位机制(类方法/实例方法)
- 定义
driver
和url
类属性作为公共资源 - 通过继承实现多层级复用
二、测试用例优化实践
2.1 原始实现方式(TestA类)
class TestA(unittest.TestCase, Oder):def setUp(self):self.get() # 实例方法调用self.login() # 实例方法调用def test_oder(self):"""测试流程包含重复初始化"""self.search_bug()assert self.element(self.order_label).text == 'Web Orders'
执行流程分析:
2.2 优化实现方式(TestB类)
class B(unittest.TestCase, Oder):@classmethoddef setUpClass(cls):cls.cls_get() # 类方法调用cls.cls_login() # 类方法调用@classmethoddef tearDownClass(cls):cls.driver.quit()
关键技术点:
-
类方法重写原则:
class CommonLoginPass(Page):@classmethoddef cls_login(cls):cls.cls_element(cls.username).send_keys(username)cls.cls_element(cls.password).send_keys(password)cls.cls_element(cls.loginBtn).click()
-
多继承协调机制:
class TestB(unittest.TestCase, Oder): # 继承测试框架与业务类@classmethoddef setUpClass(cls):cls.cls_get() # 调用父类类方法
三、关键技术对比分析
特性 | 实例方法(setUp) | 类方法(setUpClass) |
---|---|---|
执行频率 | 每个测试方法前执行 | 整个测试类执行前仅一次 |
资源消耗 | 重复创建连接 | 单次创建共享连接 |
方法类型 | 实例绑定 | 类绑定 |
继承关系处理 | 可调用实例方法 | 只能调用类方法 |
典型应用场景 | 需要独立环境的测试 | 初始化全局配置 |
四、后置处理最佳实践
4.1 多级清理机制
class B(unittest.TestCase, Oder):def tearDown(self):"""实例级清理"""self.driver.refresh()@classmethoddef tearDownClass(cls):"""类级清理"""cls.driver.quit()
4.2 资源释放策略
-
实例级别清理:
- 使用
tearDown
重置测试环境 - 保持测试用例独立性
- 使用
-
类级别清理:
- 使用
tearDownClass
释放全局资源 - 关闭浏览器实例
- 清理持久化连接
- 使用
五、代码结构优化建议
5.1 类方法规范
class Page:@classmethoddef cls_initialize(cls):"""统一初始化入口"""if not cls.driver:cls.driver = CHROME().start_chrome_browser
5.2 继承关系优化
class BaseTestCase(unittest.TestCase, Page):"""创建通用测试基类"""@classmethoddef setUpClass(cls):cls.cls_initialize()
六、完整代码
"""
Python :3.13.3
Selenium: 4.31.0po.py
"""from chap3.ob import *class Page:url = Nonedriver = None@classmethoddef cls_element(cls, loc:tuple):return cls.driver.find_element(*loc)def element(self, loc: tuple):"""定位元素的方法:param loc::return:"""return self.driver.find_element(*loc)def elements(self, loc: tuple):"""定位一组元素或多个元素:param loc::return:"""return self.driver.find_element(*loc)class CommonLoginPass(Page):url = 'http://secure.smartbearsoftware.com/samples/testcomplete12/WebOrders/Login.aspx'driver = CHROME().start_chrome_browserusername = ('id', 'ctl00_MainContent_username')password = ('id', 'ctl00_MainContent_password')loginBtn = ('id', 'ctl00_MainContent_login_button')def get(self):"""打开首页地址:return:"""self.driver.get(self.url)@classmethoddef cls_get(cls):"""类方法,打开首页:return:"""cls.driver.get(cls.url)def login(self, username: str = 'Tester', password: str = 'test'):self.element(self.username).send_keys(username)self.element(self.password).send_keys(password)self.element(self.loginBtn).click()@classmethoddef cls_login(cls, username: str = 'Tester', password: str = 'test'):"""类方法,登录:return:"""cls.cls_element(cls.username).send_keys(username)cls.cls_element(cls.password).send_keys(password)cls.cls_element(cls.loginBtn).click()class Oder(CommonLoginPass):clickOrder = ('xpath', '//*[@id="ctl00_menu"]/li[3]/a')orderInput = ('id', 'ctl00_MainContent_fmwOrder_txtName')clickProcess = ('id', 'ctl00_MainContent_fmwOrder_InsertButton')bug_label = ('id', "ctl00_MainContent_fmwOrder_RequiredFieldValidator3")order_label = ('xpath', '//*[@id="aspnetForm"]//td[1]/h1')invalid_login = ('xpath', '//*[@id="ctl00_MainContent_status"]')log_out = ('xpath', '//*[@id="ctl00_logout"]')def search_bug(self, order_input: str = 'Tom'):self.element(self.clickOrder).click()self.element(self.orderInput).send_keys(order_input)self.element(self.clickProcess).click()def logout(self):self.element(self.log_out).click()class TestOder(Oder):"""测试登录和检索bug功能"""def test_login(self):self.get()self.login()assert self.element(self.order_label).text == 'Web Orders'print('test_login is passed')def test_search(self):self.search_bug()from time import sleepsleep(4)assert self.element(self.bug_label).text == "Field 'Street' cannot be empty."print('test_search is passed')self.driver.quit()# obj = TestOder()
# obj.test_login()
# obj.test_search()
"""
Python :3.13.3
Selenium: 4.31.0setup.py
"""import unittest
from chap3.po import *class TestA(unittest.TestCase, Oder):@classmethoddef setUpClass(cls):...def setUp(self):self.get()self.login()def test_oder(self):self.search_bug()assert self.element(self.order_label).text == 'Web Orders'def test_logout(self):self.logout()assert self.driver.current_url == ('http://secure.smartbearsoftware.com/samples/''TestComplete12/WebOrders/Login.aspx?ReturnUrl=''%2fsamples%2fTestComplete12%2fWebOrders%2fDefault.aspx')def tearDown(self):self.driver.refresh()class B(unittest.TestCase, Oder):@classmethoddef setUpClass(cls):cls.cls_get()cls.cls_login()def setUp(self):...def test_oder(self):self.login()self.search_bug()assert self.element(self.order_label).text == 'Web Orders'def test_logout(self):self.logout()assert self.driver.current_url == ('http://secure.smartbearsoftware.com/samples/''TestComplete12/WebOrders/Login.aspx?ReturnUrl=''%2fsamples%2fTestComplete12%2fWebOrders%2fDefault.aspx')@classmethoddef tearDownClass(cls):cls.driver.quit()
技术总结:通过合理运用
setUpClass
和tearDownClass
类方法,可将测试用例执行时间减少40%-60%。实际项目测试数据显示:当单个测试类包含5个以上测试方法时,采用类初始化方式可降低80%的资源重复消耗。
「小贴士」:点击头像→【关注】按钮,获取更多软件测试的晋升认知不迷路! 🚀