一, Unittest 单元测试框架简介
Unitest 是 Python 下的一个单元测试模块, 是 Python 标准库模块之一, 安装完 Python 后就可以直接 import 该模块, 能在单元测试下编写具体的测试用例脚本, 并调用模块封装好的方法, 实现测试用例的执行, 测试场景的恢复, 甚至能批量采集测试用例脚本, 批量运行测试脚本用例, 控制执行顺序等, 依托于 Unittest 模块, 可以高效的组织测试用例编写, 测试用例脚本的采集管理以及脚本运行的执行控制等. Unitest 单元测试框架主要包含如下几个重要的逻辑单元:
1. 测试固件(test fixture)
一个测试固件包括两部分, 执行测试代码的前置条件和测试结束之后的场景恢复, 这两部分一般用函数 setUp()和 tearDown()表示. 简单说, 就是平时手工测试一条具体的测试用例时, 测试的前置环境和测试结束后的环境恢复.
2. 测试用例(test case)
unittest 中管理的最小单元是测试用例, 就是一个测试用例, 包括具体测试业务的函数或者方法, 只是该 test case 必须是以 test 开头的函数. unittest 会自动化识别 test 开头的函数是测试代码, 如果你写的函数不是 test 开头, unittest 是不会执行这个函数里面的脚本, 这个千万要记住, 所有的测试函数都要 test 开头, 记住是小写的哦.
3. 测试套件 (test suite)
就是很多测试用例的集合, 一个测试套件可以随意管理多个测试用例, 该部分用来实现诸多测试用例的采集, 形成一套测试用例集.
4. 测试执行器 (test runner)
test runner 是一个用来执行加载测试用例, 并执行用例, 且提供测试输出的一个逻辑单元. test runner 可以加载 test case 或者 test suite 进行执行测试任务, 并能控制用例集的执行顺序等.
从 Unitest 单元测试框架的基本逻辑单元设计来看, 很明显可以看到它包含了用例的整个生命周期: 用例的前置条件, 用例的编写, 用例的采集, 用例的执行以及测试执行后的场景恢复.
二, 首次使用 Unittest 模块
下面以打开百度, 进行搜索, 创建一个名为 baidu_search.py 的脚本文件, 编写百度搜索分别 python2 和 python3 的测试用例, 代码如下:
- '''
- Code description:
- Create time:
- Developer:
- '''
- # -*- coding: utf-8 -*-
- import time
- import unittest
- from selenium import webdriver
- class Search(unittest.TestCase):
- def setUp(self):
- """
- 测试前置条件, 这里要搜索的话就是先得打开百度网站啦
- """
- self.driver = webdriver.IE()
- self.driver.maximize_window()
- self.driver.implicitly_wait(5)
- self.driver.get("https://www.baidu.com")
- def tearDown():
- """
- 测试结束后环境复原, 这里就是浏览器关闭退出
- """
- self.driver.quit()
- def test_search1(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').send_keys('python2')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python2' in self.driver.title
- print('检索 python2 完成')
- except Exception as e:
- print('检索失败', format(e))
- def test_search2(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').send_keys('python3')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python3' in self.driver.title
- print('检索 python3 完成')
- except Exception as e:
- print('检索失败', format(e))
- if __name__ == '__main__':
- unittest.main()
在 PyCharm 中运行上面代码, 我们会发现浏览器打开关闭了两次, 分别检索了 python2 关闭浏览器, 然后检索 python3 关闭浏览器.
这个效果显然不是我们希望的, 我们希望检索完 python2 后, 不用关闭浏览器继续检索 python3,Unittest 有相关的设置吗? 答案是肯定的, 我们对以上代码做下调整修改, 注意对比不同的地方, 然后运行就达到我们想要的效果
- '''
- Code description:
- Create time:
- Developer:
- '''
- # -*- coding: utf-8 -*-
- import time
- import unittest
- from selenium import webdriver
- class Search(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- """
- 测试前置条件, 这里要搜索的话就是先得打开百度网站啦
- """
- cls.driver = webdriver.IE()
- cls.driver.maximize_window()
- cls.driver.implicitly_wait(5)
- cls.driver.get("https://www.baidu.com")
- @classmethod
- def tearDownClass(cls):
- """
- 测试结束后环境复原, 这里就是浏览器关闭退出
- """
- cls.driver.quit()
- def test_search1(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').send_keys('python2')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python2' in self.driver.title
- print('检索 python2 完成')
- except Exception as e:
- print('检索失败', format(e))
- def test_search2(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').clear() # 清空之前输入的 python2
- self.driver.find_element_by_id('kw').send_keys('python3')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python3' in self.driver.title
- print('检索 python3 完成')
- except Exception as e:
- print('检索失败', format(e))
- if __name__ == '__main__':
- unittest.main()
三, Unittest 模块批量加载和管理用例
以上对于 Unittest 框架, 我们好像只用到了测试固件, 测试用例两个逻辑单元的使用, 接下来问题又来了: 我们日常项目中的测试案例肯定不止一个, 当案例越来越多时我们如何管理这些批量案例? 如何保证案例不重复? 如果案例非常多 (成百上千, 甚至更多) 时如何保证案例执行的效率?
来看一下在 unittest 框架中如何管理批量用例:
手动添加采集指定的测试用例集用法: 先在 PyCharm 中新建如下项目层级:
其中 baidu_search1 还是上面调整修改过的代码, 然后编辑 run_case.py 文件, 代码如下:
- '''
- Code description: 执行 add 的测试用例集
- Create time:
- Developer:
- '''
- # -*- coding: utf-8 -*-
- from testcase.sreach.baidu_sreach1 import Search # 将 baidu_sreach.py 模块导入进来
- import unittest
- suite = unittest.TestSuite() # 构造测试用例集
- # suite.addTest(Search("test_search1"))
- suite.addTest(Search("test_search2")) # 分别添加 baidu_sreach1.py 中的两个检索的测试用例
- if __name__ == '__main__':
- runner = unittest.TextTestRunner() # 实例化 runner
- runner.run(suite) #执行测试
这样运行 run_case.py, 就只执行了在百度中搜索 python3 这条用例, 手动添加指定用例到测试套件的方法是 addTest(), 但是很多时候我们写了很多测试脚本文件, 每个脚本中有多个 test,, 如果还是使用 addTest()方法就不行了, 我们希望能获取所有的测试集, 并全部执行. 然后编辑 run_all_case.py 文件, 编写如下代码:
- '''
- Code description: TestLoader 所有测试 case
- Create time:
- Developer:
- '''
- # -*- coding: utf-8 -*-
- import time
- import os.path
- import unittest
- from selenium import webdriver
- class Search(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- """
- 测试前置条件, 这里要搜索的话就是先得打开百度网站啦
- """
- cls.driver = webdriver.IE()
- cls.driver.maximize_window()
- cls.driver.implicitly_wait(5)
- cls.driver.get("https://www.baidu.com")
- @classmethod
- def tearDownClass(cls):
- """
- 测试结束后环境复原, 这里就是浏览器关闭退出
- """
- cls.driver.quit()
- def test_search1(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').send_keys('python2')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python2' in self.driver.title
- print('检索 python2 完成')
- except Exception as e:
- print('检索失败', format(e))
- def test_search2(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').clear() # 清空之前输入的 python2
- self.driver.find_element_by_id('kw').send_keys('python3')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'python3' in self.driver.title
- print('检索 python3 完成')
- except Exception as e:
- print('检索失败', format(e))
- def test_search3(self):
- """
- 这里一定要 test 开头, 把测试逻辑代码封装到一个 test 开头的方法里.
- """ self.driver.find_element_by_id('kw').clear() # 清空之前输入的 python3
- self.driver.find_element_by_id('kw').send_keys('hello world')
- self.driver.find_element_by_id('su').click()
- time.sleep(1)
- try:
- assert 'hello world' in self.driver.title
- print('检索 hello world 完成')
- except Exception as e:
- print('检索失败', format(e))
- case_path = os.path.join(os.getcwd()) # 在当前目录中采集测试用例
- print(case_path)
- all_case = unittest.defaultTestLoader.discover(case_path, pattern="test*.py", top_level_dir=None) # 采集所有 test 开头的测试用例
- print(all_case)
- if __name__ == '__main__':
- runner = unittest.TextTestRunner() # 实例化 runner
- runner.run(all_case) # 执行测试
获取所有的测试用例集使用的是 discover()方法, 在 PyCharm 中运行该脚本就如下:
以上就完成了在 Python Unittest 单元测试框架下编写测试用例脚本, 并使用其提供的多种方法来批量管理测试用例集并并执行.
来源: https://www.cnblogs.com/tdp0108/p/10541445.html