持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
unitest是Python内置模块,帮助代码实现单元测试,并生成测试报告。
基本使用
# 使用注意点
# 1. 测试类必须继承unitest.TestCase
# 2. 在测试类中的每个方法或者函数如果是需要被执行的,方法名或者函数名必须以test开头
import unittest
def my_sum(a, b):
return a + b
class MyTestCase(unittest.TestCase):
@staticmethod
def test01():
print(my_sum(1, 2))
@staticmethod
def test02():
print(my_sum(3, 4))
testsuite使用
在实际工作中,将所有的测试用例都放在同一个类下面是不切合实际的,可以借助testsuite将测试用例从其他文件中加载过来,然后执行,还需要借助TextTestRunner运行这些测试用例。
import unittest
import testcase
suite = unittest.TestSuite() # 生成测试套件,可以理解为装测试用例的容器
suite.addTest(testcase.MyTestCase("test01")) # 向容器中添加测试用例
suite.addTest(testcase.MyTestCase("test02"))
runner = unittest.TextTestRunner() # 生成运行测试用例的工具
runner.run(suite) # 运行测试用例
使用上述方式虽然解决了将其他文件中的测试用例一起执行的问题,但是如果有非常多的测试用例,每次都通过addTest方法添加会出现大量重复代码,可以借助makeSuite方法将测试用例以类为单位添加到测试套件中,这种方式相对于addTest会节省很多代码。
import unittest
import testcase
suite = unittest.makeSuite(testCaseClass=testcase.MyTestCase)
runner = unittest.TextTestRunner() # 生成运行测试用例的工具
runner.run(suite) # 运行测试用例
说了这么多,以上方法都是不常用的!!!
常用的是TestLoader(),可以将测试用例以文件为单位加入到套件中,使用方式也更加简单:
import unittest
import testcase
suite = unittest.TestLoader().discover(r"./", "test*.py") # 生成测试套件,装测试用例的容器,并且加载py文件中的测试用例,意思是将当前目录下以test开头的py文件中只的所有测试用例都加载到测试套件中
runner = unittest.TextTestRunner() # 生成运行测试用例的工具
runner.run(suite) # 运行测试用例
TestSuite和TestLoader的使用区别
- 当只是要执行py文件中多个测试用例中的几个,而不是全部执行那么适合用TestSuite的addTest加载指定的测试用例
- 当要执行所有的py文件中的所有的测试用例,那么适合使用TestLoader
Fixture
-
可以在测试用例执行执行之前自动调用指定的函数,在测试用例执行之后自动调用指定的函数
-
控制级别
-
方法级
- 每个方法执行前和执行后都自动调用函数
-
类级
- 不管类中有多少方法,一个类执行前后都自动调用函数
-
模块级
- 不管一个模块(一个模块就是一个py文件)中有多少类,模块执行前后自动调用函数
-
方法级
- 在TestCase,也就是测试用例所在的class中定义方法
- def setUp(self) 当测试用例执行前,自动被调用
- def tearDown(self) 当测试用例执行后,自动被调用
- 如果一个TestCase中有多个测试用例,那么setUp和tearDown就会被自动调用多次
mytest.py内容修改如下:
import unittest
def my_sum(a, b):
return a + b
class my_test(unittest.TestCase):
def setUp(self):
print("setup被自动调用了")
def tearDown(self):
print("teardown被自动调用了")
def test_001(self):
print(my_sum(5, 6))
def test_002(self):
print(my_sum(0, 3))
类级
- 不管类中有多少方法,一个类开始的时候自动调用函数,结束的之后自动调用函数
- 类级的fixture一定要是类方法
@classmethod def setUpClass(cls)类开始时自动调用的方法@clasmethod def tearDownClass(cls)类结束的时候自动调用的方法
mytest.py修改如下:
import unittest
def my_sum(a, b):
return a + b
class my_test(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setupclass自动调用了")
@classmethod
def tearDownClass(cls):
print("teardownclass自动调用了")
def setUp(self):
print("setup被自动调用了")
def tearDown(self):
print("teardown被自动调用了")
def test_001(self):
print(my_sum(5, 6))
def test_002(self):
print(my_sum(0, 3))
模块级
- 不管py文件中有多少个类,以及类中有多少方法,只自动执行一次
- def setUpModule() 在py文件开始的时候自动调用
- def tearDownModule() 在py文件结束的时候自动调用
修改后的mytest.py内容如下
import unittest
def setUpModule():
print("setUpModule自动调用了")
def tearDownModule():
print("tearDownModule自动调用了")
def my_sum(a, b):
return a + b
class my_test1(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setupclass自动调用了")
@classmethod
def tearDownClass(cls):
print("teardownclass自动调用了")
def setUp(self):
print("setup被自动调用了")
def tearDown(self):
print("teardown被自动调用了")
def test_001(self):
print(my_sum(5, 6))
def test_002(self):
print(my_sum(0, 3))
class my_test2(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setupclass自动调用了")
@classmethod
def tearDownClass(cls):
print("teardownclass自动调用了")
def setUp(self):
print("setup被自动调用了")
def tearDown(self):
print("teardown被自动调用了")
def test_001(self):
print(my_sum(5, 6))
def test_002(self):
print(my_sum(0, 3))
fixture小结
- 一定要在继承于unittest.TestCase这个类的子类中使用
- setUP,tearDown, 每个方法执行开始和完毕后自动调用
- setUPClass, tearDownClass, 每个类开始时候和结束时候自动调用
- setUpModule, tearDownModule,每个py文件开始和结束的时候自动调用
断言
断言的方法在unitest.TestCase()中已经定义好,因此在测试类中的方法直接使用即可。
import unittest
def my_sum(a, b):
return a + b
class MyTestCase(unittest.TestCase):
def test01(self):
self.assertEquals(10, my_sum(5, 5))
参数化
多个测试用例代码相同,只是测试数据不同,预期结果不同,可以把多个测试用例通过参数化技术合并为一个测试用例,这个时候我们就可以使用参数化实现这种需求。
使用参数化需要记住第三方包parameterized,使用方式如下
import unittest
from parameterized import parameterized
def my_sum(a, b):
return a + b
class MyTestCase(unittest.TestCase):
# 使用装饰器将不同的组合值写入到列表中,列表中的元组放的是不同的组合
# 执行时将列表打散得到不同的元组,再将元组中的值打散传递给测试方法
@parameterized.expand([(1, 1, 2), (2, 2, 4)])
def test01(self, a, b, c):
"""
:param a: first param
:param b: second param
:param c: result
:return: None
"""
self.assertEquals(c, my_sum(a, b))
跳过某个测试用例
# 不希望执行某个测试用例的时候可以使用
class MyTestCase(unittest.TestCase):
@unittest.skip("不想执行")
# @unittest.skipIf(True, "没写好") # @unitest.skipIf(condition, reason) 当condition为True时,返回reason
def test02(self):
self.assertEquals(1, my_sum(1, 1))
生成测试报告
TextTestRunner(比较丑很少使用)
import unittest
suite = unittest.TestLoader().discover(r"./", "testc*.py") # 生成测试套件,装测试用例的容器,并且加载py文件中的测试用例
with open("test.txt", "w", encoding="utf8") as f:
runner = unittest.TextTestRunner(stream=f, verbosity=2) # 生成运行测试用例的工具,将产生的测试用例结果写到文件中
runner.run(suite) # 运行测试用例
HtmlTestRunner
import unittest
from HtmlTestRunner import HTMLTestRunner
suite = unittest.TestLoader().discover(r"./", "testc*.py") # 生成测试套件,装测试用例的容器,并且加载py文件中的测试用例
with open("test.txt", "w", encoding="utf8") as f:
runner = HTMLTestRunner(stream=f, report_title="test.html") # 生成运行测试用例的工具,将产生的测试用例结果写到文件中
runner.run(suite) # 运行测试用例
\