一谈及unittest,大家都知道,unittest是Python中自带的单元测试框架,它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作。unittest单元测试框架不仅可以适用于单元测试,还可以适用web自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果。
在聊unittest时,需要先明白,最基础的四个概念:TestCase,TestSuite,TestRunner,TestFixture,看如下静态图:
unittest运行流程
先编写好TestCase,然后由TestLoader加载TestCase到TestSuite,其次由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。
unittest模块的各个属性说明
unittest.TestCase:TestCase类,所有测试用例类继承的基本类。
class BaiduTest(unittest.TestCase):
unittest.main():使用它可以方便的将一个单元测试模块变为可直接运行的测试脚本,main()方法使用TestLoader类来搜索所有包含在该模块中以“test”命名开头的测试方法,并自动执行他们。执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。所以以A开头的测试用例方法会优先执行,以a开头会后执行。
unittest.TestSuite():unittest框架的TestSuite()类是用来创建测试套件的。
unittest.TextTextRunner():unittest框架的TextTextRunner()类,通过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。
unittest.defaultTestLoader(): defaultTestLoader()类,通过该类下面的discover()方法可自动更具测试目录start_dir匹配查找测试用例文件(test*.py),并将查找到的测试用例组装到测试套件,因此可以直接通过run()方法执行discover。用法如下:
discover=unittest.defaultTestLoader.discover(test_dir, pattern=‘test_*.py’)
unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是比如说想调试某一个测试用例,想先屏蔽其他用例就可以用装饰器屏蔽。
@unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的原因。
@unittest.skipIf(reason):skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的原因。
@unittest.skipUnless(reason):skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的原因。
@unittest.expectedFailure():expectedFailure()测试标记为失败。
setUp():setUp()方法用于每个测试用例执行前的初始化工作。如测试用例中需要访问数据库,可以在setUp中建立数据库连接并进行初始化。如测试用例需要登录web,可以先实例化浏览器。
tearDown():tearDown()方法用于每个测试用例执行之后的善后工作。如关闭数据库连接、关闭浏览器。
setUpClass():setUpClass()方法用于所有测试用例前的设置工作。
tearDownClass():tearDownClass()方法用于所有测试用例执行后的清理工作。
addTest():addTest()方法是将测试用例添加到测试套件中。
run():run()方法是运行测试套件的测试用例,入参为suite测试套件。
assert*():在执行测试用例的过程中,最终用例是否执行通过,是通过判断测试得到的实际结果和预期结果是否相等决定的。
断言方式如下:
assertEqual(a,b,[msg=‘测试失败时打印的信息’]):断言a和b是否相等,相等则测试用例通过。
assertNotEqual(a,b,[msg=‘测试失败时打印的信息’]):断言a和b是否相等,不相等则测试用例通过。
assertTrue(x,[msg=‘测试失败时打印的信息’]):断言x是否True,是True则测试用例通过。
assertFalse(x,[msg=‘测试失败时打印的信息’]):断言x是否False,是False则测试用例通过。
assertIs(a,b,[msg=‘测试失败时打印的信息’]):断言a是否是b,是则测试用例通过。
assertNotIs(a,b,[msg=‘测试失败时打印的信息’]):断言a是否是b,不是则测试用例通过。
assertIsNone(x,[msg=‘测试失败时打印的信息’]):断言x是否None,是None则测试用例通过。
assertIsNotNone(x,[msg=‘测试失败时打印的信息’]):断言x是否None,不是None则测试用例通过。
assertIn(a,b,[msg=‘测试失败时打印的信息’]):断言a是否在b中,在b中则测试用例通过。
assertNotIn(a,b,[msg=‘测试失败时打印的信息’]):断言a是否在b中,不在b中则测试用例通过。
assertIsInstance(a,b,[msg=‘测试失败时打印的信息’]):断言a是是b的一个实例,是则测试用例通过。
assertNotIsInstance(a,b,[msg=‘测试失败时打印的信息’]):断言a是是b的一个实例,不是则测试用例通过。
说了这么多的属性,接下来用一段代码举例:
unittest基本代码示例:
复制代码
import unittest
from unittestbasic1.unittest_operation import *
‘’’
@author: wenyihuqingjiu
@project: unittestdemo
@file: unittest_demo_basic.py
@time: 2019-09-26 23:38
@desc:
‘’’
class TestMathFunc(unittest.TestCase):
# TestCase基类方法,所有case执行之前自动执行
@classmethod
def setUpClass(cls):
print("*************这里是所有测试用例前的准备工作*************")
# TestCase基类方法,所有case执行之后自动执行
@classmethod
def tearDownClass(cls):
print("*************这里是所有测试用例后的清理工作*************")
# TestCase基类方法,每次执行case前自动执行
def setUp(self):
print("-------------这里是一个测试用例前的准备工作-------------")
# TestCase基类方法,每次执行case后自动执行
def tearDown(self):
print("-------------这里是一个测试用例后的清理工作-------------")
@unittest.skip("我想临时跳过这个测试用例.")
def test_add(self):
self.assertEqual(3, add(1, 2))
self.assertNotEqual(3, add(2, 2)) # 测试业务方法add
def test_minus(self):
self.skipTest('跳过这个测试用例')
self.assertEqual(1, minus(3, 2)) # 测试业务方法minus
def test_multi(self):
self.assertEqual(6, multi(2, 3)) # 测试业务方法multi
def test_divide(self):
self.assertEqual(2, divide(6, 3)) # 测试业务方法divide
self.assertEqual(2.5, divide(5, 2))
if name == ‘main’:
unittest.main(verbosity=2)
复制代码
基本函数如下:
复制代码
def add(a, b):
return a+b
def minus(a, b):
return a-b
def multi(a, b):
return a*b
def divide(a, b):
return a/b
复制代码
运行代码,结果如下所示:
理论加实践,结合起来看,应该更容易明白些,切莫做纸上谈兵。
添加用例运行方式
弄明白了unittest的基本属性,接下来分享下添加用例运行的不同方式
方式一:使用addTests单个添加
用addTests方法单个添加用例,代码示例如下:
复制代码
import unittest
from unittestbasic2.unittest_operation2 import TestMathFunc
‘’’
@author: wenyihuqingjiu
@project: unittestdemo
@file: unittest_demo_suite1.py
@time: 2019-09-26 23:38
@desc:
‘’’
if name == ‘main’:
suite = unittest.TestSuite()
# 单个添加测试用例
suite.addTest(TestMathFunc(“test_multi”))
suite.addTest(TestMathFunc(“test_divide”))
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
复制代码
方式二:测试用例添加到用例集中
从方法一种看,单个添加用例比较麻烦,该方法可以将用例添加到一个用例集中,再通过suite统一运行,代码示例如下:
复制代码
import unittest
from unittestbasic2.unittest_operation2 import TestMathFunc
‘’’
@author: wenyihuqingjiu
@project: unittestdemo
@file: unittest_demo_suite2.py
@time: 2019-09-26 23:38
@desc:
‘’’
if name == ‘main’:
suite = unittest.TestSuite()
# 将测试用例添加到一个用例集中
tests = [TestMathFunc(“test_add”), TestMathFunc(“test_minus”)]
suite.addTests(tests) # 将测试用例列表添加到测试组中
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
复制代码
方式三:TestLoader方法加载用例
使用TestLoader方法加载用例,就是无法对case进行排序,执行顺序是随机的。实现方法有如下三种,代码示例如下:
复制代码
import unittest
from unittestbasic2.unittest_operation2 import TestMathFunc
‘’’
@author: wenyihuqingjiu
@project: unittestdemo
@file: unittest_demo_suite3.py
@time: 2019-09-26 23:44
@desc:
‘’’
if name == ‘main’:
suite = unittest.TestSuite()
# 第一种方法:传入’模块名.TestCase名’
# 用addTests + TestLoader。不过用TestLoader的方法是无法对case进行排序的
# loadTestsFromName(),传入’模块名.TestCase名’
# ①
# suite.addTests(unittest.TestLoader().loadTestsFromName(‘unittest_operation2.TestMathFunc’))
# suite.addTests(unittest.TestLoader().loadTestsFromName(‘unittest_operation1.TestMathFunc’))
# 这里还可以把’模块名.TestCase名’放到一个列表中
# ②
# suite.addTests(unittest.TestLoader().loadTestsFromNames([‘unittest_operation2.TestMathFunc’, ‘unittest_operation1.TestMathFunc’]))
# 第二种方法:传入TestCase 需要导入对应模块
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
深圳网站建设www.sz886.com