1. 单元测试概述
通常用于判断某个特定条件(或场景)下某个特定函数的行为。
2. 单元测试框架
-
Unittest – Python内置的标准类库。其API与JAVA的JUnit类似
-
Pytest – 更加丰富、灵活,语法简单。可以结合Allure生成酷炫的测试报告
-
Nose–对unittest的扩展
-
Mock
3. 常用的单元测试覆盖类型
ex,如下被测代码片段:
def demo_method(a,b,x):
if (a > 1 and b == 0):
x = x / a
if (a == 2 or x > 1):
x = x + 1
return x
-
语句覆盖:保证被测方法的每一行代码都被执行一遍
-
用例条数:1条
-
用例:a=3,b=0,x=4
-
漏洞:and 写为 or的情况,无法识别出
-
特点:未考虑内部逻辑,最基础、最薄弱。完全依赖行覆盖会出现严重问题
-
-
判断覆盖:使得每一个判定获得每一种可能的结果
-
用例条数:4条(判定语句个数×单条语句可能结果数)
-
漏洞:a==2 or x>1 写为 a==2 or x<1 的情况,无法识别出
-
特点:仅判断整个判断语句的结果,未考虑其内部的逻辑条件组合,会遗漏
-
-
条件覆盖:使得每一个表达式获得每一种可能的结果
-
用例条数:16条(表达式个数×单条语句可能结果数)
-
特点:用例指数级增长
-
-
路径覆盖:覆盖所有可能执行的路径
4. unittest框架
4.1 unittest组件(官网 https://docs.python.org/3/library/unittest.html )
-
test fixture - 测试装置。完成测试前准备、测试后清理操作
-
test case - 测试用例
-
test suite - 测试套件
-
test runner - 运行器。执行测试和提供结果
4.2 unittest编写规范
-
测试模块首先 import unittest
-
测试类必须继承 unittest.TestCase
-
测试方法必须以 test 开头
Basic example:
import unittest
class TestStringMethods(unittest.TestCase):
def test01_upper(self):
print("111")
self.assertEqual('foo'.upper(), 'FOO')
# assert 'foo'.upper() == 'FOO'
def test02_isupper(self):
print("222")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test03_split(self):
print("333")
s = 'hello world'
#以空格为分隔符,分隔成3个单词
# print(s.split(' ',2))
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
#所传分隔符需要为str格式,不能是int,否则会抛出TypeError异常
s.split(2)
if __name__ == '__main__':
unittest.main()
- setUp() - 测试环境准备,在每一个测试方法前运行
- tearDown() - 测试环境清理,在每一个测试方法后运行
- setUpClass() - 在当前测试类的所有测试方法执行前运行
- tearDownClass() - 在当前测试类的所有测试方法执行后运行
4.3 unittest常用断言&&用例执行方式
-
方式一:执行当前文件所有的unittest测试用例,全部执行
-
方式二:执行指定的测试用例 - 将要执行的测试用例添加到测试套件中,批量执行测试方法
-
方式三:执行指定的测试类 - 将测试类添加到测试套件里面, 批量执行测试类
-
方式四:匹配某个目录下所有满足unittest规则的测试用例,执行这些py文件下的所有测试用例
#1、setUp、tearDown、setUpClass、tearDownClass方法练习
#2、unittest常用断言的使用
#3、执行测试用例方法
import unittest
#被测试方法
class Search():
def search_func(self):
print("search")
return True
class TestSearch(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('setupclass')
cls.search = Search()
@classmethod
def tearDownClass(cls):
print('teardownclass')
def test_search1(self):
print("testsearch1")
# search = Search()
assert True == self.search.search_func()
def test_search2(self):
print("testsearch2")
# search = Search()
assert True == self.search.search_func()
def test_search3(self):
print("testsearch3")
# search = Search()
assert True == self.search.search_func()
class TestSearch1(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('setupclass1')
cls.search = Search()
@classmethod
def tearDownClass(cls):
print('teardownclass1--1')
def test_search1(self):
print("testsearch1--1")
# search = Search()
assert True == self.search.search_func()
def test_search2(self):
print("testsearch2--1")
# search = Search()
assert True == self.search.search_func()
def test_search3(self):
print("testsearch3--1")
# search = Search()
assert True == self.search.search_func()
def test00(self):
self.assertIsInstance(self.search,Search,"search is for Search")
self.assertNotIsInstance(2, Search,"2 is not for Search")
if __name__ == '__main__':
#方式一:执行当前文件所有的unittest测试用例,全部执行
unittest.main()
#方式二:执行指定的测试用例,将要执行的测试用例添加到测试套件里面,批量执行测试方法
#创建一个测试套件,testsuite
suite = unittest.TestSuite()
#将测试用例添加到测试套件中
suite.addTest(TestSearch1("test00"))
suite.addTest(TestSearch1("test_search3"))
#使用unittest.TextTestRunner()方法执行suite套件
unittest.TextTestRunner().run(suite)
#方式三:执行某个测试类,将测试类添加到测试套件里面, 批量执行测试类
#将测试类添加到测试套件中
suite1 = unittest.TestLoader().loadTestsFromTestCase(TestSearch)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestSearch1)
#创建一个测试套件
suite = unittest.TestSuite([suite1,suite2])
unittest.TextTestRunner(verbosity=2).run(suite)
#方式二和方式三都需要创建测试套,区别在于添加用例的方式不同,一个是用addTest方法,添加测试类中的测试用例;一个是是用TestLoader添加测试类
#将要执行的用例全部添加到测试套件suite后,就可以运行套件从而执行用例
#方式四:匹配某个目录下所有满足unittest规则的测试用例,执行这些py文件下的所有测试用例
import unittest
#入口方法
if __name__ == '__main__':
#在当前路径下找到要执行的模块路径
test_dir = "./testcases"
#将要执行的所有用例添加到discover
discover = unittest.defaultTestLoader.discover(test_dir,pattern="test*.py")
unittest.TextTestRunner().run(discover)
4.4 unittest 结合 htmltestrunner 生成测试报告
import unittest
from util.HTMLTestRunner_PY3 import HTMLTestRunner
if __name__ == '__main__':
report_title = 'Example用例执行报告'
desc = '用于展示修改样式后的HTMLTestRunner'
report_file = './result.html'
#在当前路径下找到要执行的发现路径
test_dir = "./testcases"
#将要执行的所有用例添加到discover
discover = unittest.defaultTestLoader.discover(test_dir,pattern="test*.py")
with open(report_file, 'wb') as report:
runner = HTMLTestRunner(stream=report, title=report_title, description=desc)
runner.run(discover)
在浏览器查看测试报告 result.html :