unittest原名为PyUnit,是由java的JUnit衍生而来。unittest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。unittest作为官方的测试框架,在测试方面非常基础,可以在此基础上进行二次开发。
先通过一个简单的示例,对unittest有一个直观的了解:
import unittest
class Mytest1(unittest.TestCase):
def setUp(self) -> None:
print("===== setUp =====")
def tearDown(self) -> None:
print("===== tearDown =====")
@classmethod
def setUpClass(cls) -> None:
print("===== setUpClass =====")
@classmethod
def tearDownClass(cls) -> None:
print("===== tearDownClass =====")
def test_add(self):
print("测试函数add")
self.name = "Aaa"
def test_down(self):
print("测试函数down")
self.name = "Bbb"
# 文件内执行方式
if __name__ == "__main__":
unittest.main()
# 命令行执行,scratch_11.py为包含
python -m unittest scratch_11.py
执行结果:
===== setUpClass =====
===== setUp =====
测试函数add
===== tearDown =====
===== setUp =====
测试函数down
===== tearDown =====
===== tearDownClass =====
通过上面的例子,我们可以总结:
测试中,我们会经常用到判断某个函数的返回结果是否等于某个值或者等于某个类型这种情况,非常适合使用断言来判断。在UnitTest中,TestCase 已经提供有封装好的断言方法进行断言校验。断言强调的是对于整个测试流程的结果进行判断,所以断言的内容是极为核心的。
有时候,测试用例很多,有些需要执行,有些不想执行,那就需要跳过一些测试用例,这时候就需要用到skip,skip用法:
示例如下:
import unittest
class Mytest1(unittest.TestCase):
def setUp(self) -> None:
print("===== setUp =====")
def tearDown(self) -> None:
print("===== tearDown =====")
@classmethod
def setUpClass(cls) -> None:
print("===== setUpClass =====")
@classmethod
def tearDownClass(cls) -> None:
print("===== tearDownClass =====")
@unittest.skip("直接跳过")
def test_1(self):
print("test_1")
@unittest.skipIf(1<2,"条件为True则跳过")
def test_2(self):
print("test_2")
@unittest.skipUnless(1<2,"条件为False则跳过")
def test_3(self):
print("test_3")
@unittest.expectedFailure
def test_4(self):
print("test_4")
self.assertEqual(4,5)
if __name__ == "__main__":
unittest.main()
执行结果如下,可以看到跳过了2个,对应test_1、test_2,test_3不满足条件,没有跳过,test_4执行错误,但是没有计入错误总数中:
ss.x
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK (skipped=2, expected failures=1)
===== setUp =====
test_3
===== tearDown =====
===== setUp =====
test_4
===== tearDown =====
结果中ss.x代表的意思:
上面的TestCase例子中,4个测试方法的执行顺序是按照1 2 3 4的顺序,如果我们想自定义执行顺序怎么办,比如2可能依赖于1,在unittest中解决用例执行顺序的问题是使用TestSuite,测试套件TestSuite的作用:
先看一个简单的示例:
from unittest import TestSuite
suite = TestSuite()
# 添加单个测试用例
suite.addTest(Mytest1("test_3"))
suite.addTest(Mytest1("test_1"))
suite.addTest(Mytest1("test_2"))
# 添加多个测试用例
cases = [Mytest1('test_3'), Mytest1('test_1'), Mytest1('test_2')]
suite.addTests(cases)
# 执行测试,unittest.TextTestRunner功能相当于unittest.main
runner = unittest.TextTestRunner()
runner.run(suite)
有时候我们需要更好的结果展示方式,可以使用HtmlTestRunner模块生成html格式的报告,安装后导入该模块,使用HTMLTestRunner代替默认的TextTestRunner()执行测试用例即可。
pip install html-testRunner
安装HtmlTestRunner模块。
示例如下:
from unittest import TestSuite
from HtmlTestRunner import HTMLTestRunner
class Mytest1(unittest.TestCase):
def test_1(self):
print("test_1")
def test_2(self):
print("test_2")
def test_3(self):
print("test_3")
def test_4(self):
print("test_4")
if __name__ == "__main__":
# 创建一个测试套件 suite
suite = TestSuite()
# 添加单个测试用例
suite.addTest(Mytest1("test_3"))
suite.addTest(Mytest1("test_1"))
suite.addTest(Mytest1("test_2"))
# 执行测试并输出html报告,output输出到xx目录下
runner = HTMLTestRunner(output="result")
runner.run(suite)
有时我们需要对大量的数据进行同一种逻辑函数测试,这时候可以用到ddt模块。
ddt,是一种 数据驱动测试 思想,数据和用例进行分离,通过外部数据去生成测试用例,可以快速的对大量数据和不同情况进行测试。
首先我们需要在python中安装ddt模块:pip install ddt
。
数据引入的方式主要有以下几种:
照常先使用一个简单示例来演示:
使用data装饰器
import unittest
from ddt import ddt, data, unpack
# 先定义@ddt,用于表示要使用ddt了
@ddt
class Mytest1(unittest.TestCase):
# data用于设定参数
@data("a", "b", "c")
def test_1(self, text):
self.assertEqual("a", text)
if __name__ == "__main__":
unittest.main()
使用json文件
先编写一个json文件:
[
{
"name": "test",
"age": 18
},
{
"name": "test1",
"age": 20
}
]
编写测试代码:
import unittest
from ddt import ddt, file_data
@ddt
class Mytest1(unittest.TestCase):
@file_data("/Users/tangliqi/Desktop/个人文档/json文件/test.json")
def test_1(self, **text):
print(text)
print(type(text))
if __name__ == "__main__":
unittest.main()
输出结果:
{'name': 'test', 'age': 18}
{'name': 'test1', 'age': 20}
使用yaml文件
编写一个yaml文件:
# "-"表示一个列表
-
name: 'test1'
age: 18
-
name: 'test2'
age: 20
编写测试代码:
import unittest
from ddt import ddt, file_data
@ddt
class Mytest1(unittest.TestCase):
@file_data("/Users/tangliqi/Desktop/个人文档/json文件/test.yaml")
def test_1(self, **text):
print(text)
print(type(text))
if __name__ == "__main__":
unittest.main()
执行结果:
{'name': 'test1', 'age': 18}
{'name': 'test2', 'age': 20}