python自带unittest框架
unittest框架
unittest
unittest是python中内置的单元测试框架(框架),不仅可以完成单元测试,也是适用于web自动化测试中。
unittest提供了丰富的断言方法,判断测试用例是否通过,然后生成测试报告
M:\tests\ # 我的是M盘的tests目录,所有操作都在tests目录内完成
├─discover
│ ├─son
│ │ ├─test_dict.py
│ │ └─__init__.py
│ ├─test_list.py
│ ├─test_str.py
│ └─__init__.py
├─loadTestsFromTestCaseDemo
│ └─loadTestsFromTestCaseDemo.py
├─case_set.py #用例集
├─myMain.py # 代码演示文件,所有演示脚本文件
├─test_tuple.py
└─__init__.py
目前这些文件都是空的,后续会一一建立,各目录内的init.py也必须建立,虽然他们都是空的,但是他无比重要,因为标明他所在目录是python的包
case_set.py有四个函数,分别计算加减乘除,并且,代码不变
""" 用例集 """ def add(x,y): """ 两数相加 :param x: :param y: :return: """ return x + y
def sub(x,y):
"""
两数相减
:param x:
:param y:
:return:
"""def mul(x,y):
"""
两数相乘
:param x:
:param y:
:return:
"""
return x*y
def div(x,y):
"""
两数相除
:param x:
:param y:
:return:
"""
return x / y
基础运行unittest
在myMain.py中
import case_set #导入用例集 import unittest #导入unittest框架
class myUnitTest(unittest.TestCase):
def setUp(self): """用例初始化""" print("用例初始化 setup") def runTest(self): """执行用例""" print(case_set.add(2,3) == 5) def tearDown(self): print("用例执行完毕,收尾")
if name == "main":
demo = myUnitTest()
demo.run() #固定的调用方法run
运行myMain.py,并且用例执行通过
用例执行流程:
setup首先在用例之前执行
接着执行用例,用例返回True
最后执行,teardown
在每个用例执行时,setup和teardown都会执行
注意:
myUnittest类名可以自定义,但是必须继承unittest.TestCase
示例中的setup和tearDown方法名是固定的,但如果,我们测试时,没有初始化和收尾的工作,setup和teardown方法可以忽略不写
至于执行用例的那个runTest方法名叫什么取决于在实例化myUniTest类时,我们来看unitest.TestCase类的init方法和run方法做了什么
class TestCase(object):
def __init__(self, methodName='runTest'): self._testMethodName = methodName self._outcome = None self._testMethodDoc = 'No test' # 也请留意这个鬼东西 No test def run(self, result=None): # run方法反射了methodName testMethod = getattr(self, self._testMethodName) #查找在这个类中有没有这个方法名
所以,runTest方法名可以自定义:
import unittest import case_set
class myUnitTest(unittest.TestCase):
def add_test(self): """ 执行用例 """ print(case_set.add(2, 3) == 5)
if name == 'main':
demo = myUnitTest(methodName='add_test')
demo.run()
unittest如何执行多用例
类的写法
import unittest import case_set
class myUnitTestAdd(unittest.TestCase):
def runTest(self): """ 执行用例 """ print(case_set.add(2, 3) == 5)
class myUnitTestSub(unittest.TestCase):
def runTest(self): """ 执行用例 """ print(case_set.sub(2, 3) == 5) # 用例结果不符合预期
if name == 'main':
demo1 = myUnitTestAdd()
demo2 = myUnitTestSub()
demo1.run()
demo2.run()
类方法的写法:
import unittest import case_set
class myUnitTest(unittest.TestCase):
def add_test(self): """ 执行用例 """ print(case_set.add(2, 3) == 5) def sub_test(self): """ 执行用例""" print(case_set.sub(10, 5) == 2)
if name == 'main':
demo1 = myUnitTest('add_test')
demo2 = myUnitTest('sub_test')
demo1.run()
demo2.run()
上面方式,每个用例都要实例化一次,虽然可以执行多个用例,但是,这么写太low,反倒没有测试触发用例来的简单。另外,用print打印也不符合真实的测试环境
我们先来解决print的问题
使用unittest提供断言
最常用的断言方式
method | checks that | description | New in |
---|---|---|---|
assertEqual(a,b,msg) | a==b | 如果a不等于b,断言失败 | |
assertNotEqual(a,b,msg) | a!=b | 如果a等于b,断言失败 | |
assertTrue(x,msg) | bool(x) is True | 如果表达式x不为True,断言失败 | |
assertFalse(x,msg) | bool(x) is False | 如果表达式不为False,断言失败 | |
assertIs(a,b,msg) | a is b | 如果a is not b,断言失败 | |
assertIsNot(a,b,msg) | a is not b | 如果a is b,断言失败 | 3.1 |
assertIsNone(x,msg) | x is not None | 如果不是None,断言失败 | 3.1 |
assertIn(a,b,msg) | a is b | 如果a not in b,断言失败 | 3.1 |
assertNotIn(a,b.msg) | a not in b | 如果a in b,断言失败 | 3.1 |
assertIsInstance(a,b,msg) | isinstance(a,b) | 如果a不是b类型,断言失败 | 3.1 |
assertNotIsInstance(a,b.msg) | not isinstance(a,b) | 如果a是b类型,断言失败 | 3.1 |
unittest简单上手
# import unittest
class MyTestCase(unittest.TestCase):
def setUp(self):
print('初始化')
def tearDown(self):
print('收尾')
def xxxTest(self):
print(11111)
if name == 'main':
obj = MyTestCase(methodName='xxxTest')
obj.run()
unittest简单断言
# import requests
#
# url = 'https://cnodejs.org/api/v1/topics'
#
# class TestCase2(unittest.TestCase):
#
# def setUp(self):
# response = requests.get(url)
# self.res = response.json()['success']
#
# def test_case_01(self):
#
# print(111111, self.res)
# # self.assertEqual(False, res, msg='预期值{} 与期望值{} 不相符'.format(False, res))
# self.assertTrue(self.res)
#
#
# def test_case_02(self):
# self.assertFalse(self.res)
#
# if __name__ == '__main__':
# unittest.main()
unitest的TestSuite测试套件的使用
- 自己实例化用例对象
- 使用TestSuite创建容器
- 自己将用例对象添加到容器中
- 使用TestTestRunner执行容器中的用例
要执行的测试用例
import unittest
class TestCase1(unittest.TestCase):
def test_case_01(self): self.assertTrue(1) def test_case_02(self): print(xxx) self.assertTrue(0) def test_case_03(self): self.assertTrue(0)
if name == 'main':
# # 1. 实例化用例对象
# case1 = TestCase1('test_case_01')
# case2 = TestCase1('test_case_02')
# case3 = TestCase1('test_case_03')
创建测试套件(用例)
使用测试套件TestSuite
方式一:
# # 2. 创建测试套件(容器)
# suite_obj = unittest.TestSuite()
# # suite_obj.addTest(case1)
# # suite_obj.addTest(case2)
unittest.TextTestRunner().run(suite_obj)
方式二:
# # for i in [case1, case2]:
# # suite_obj.addTest(i)
这种方式与上一种相同
# suite_obj.addTests([case1, case2, case3])
unittest.TextTestRunner().run(suite_obj)
方式三:
# 1. 实例化用例对象 # case1 = TestCase1('test_case_01') # case2 = TestCase1('test_case_02') # case3 = TestCase1('test_case_03') case = map(TestCase1, ['test_case_01', 'test_case_02', 'test_case_03']) # 2. 创建测试套件(容器) suite_obj = unittest.TestSuite() # suite_obj.addTest(case1) # suite_obj.addTest(case2)
# for i in [case1, case2]: # suite_obj.addTest(i) suite_obj.addTests(case) # 3. 找个执行器执行测试套件中的用例 unittest.TextTestRunner().run(suite_obj)
makeSuite的使用
import unittest
class TestCase2(unittest.TestCase):
def test_case_01(self): self.assertTrue(1) def test_case_02(self): self.assertTrue(0) def test_case_03(self): self.assertTrue(0) def my_case_01(self): self.assertTrue(1) def my_case_02(self): self.assertTrue(1)
if name == 'main':
suite = unittest.makeSuite(testCaseClass=TestCase2, prefix='test') print(33333333, suite.countTestCases()) suite.addTests(map(TestCase2, ['my_case_01', 'my_case_02'])) print(4444, suite.countTestCases()) # 执行器 unittest.TextTestRunner().run(suite)
在创建容器时,该套件自动帮我们去指定的TestCaseClass类中获取以prefix开头的用例,器执行该容器中的一个容器对象
使用例用执行
import unittest discover = unittest.TestLoader().discover( start_dir=base_dir, # 该参必传 pattern='test*.py', # 保持默认即可。 top_level_dir=None ) unittest.TextTestRunner(verbosity=2).run(discover)
该discover方法接收三个参数:
start_dir:要测试的模块名或者测试用例的目录。
pattern="test*.py":表示用例文件名的匹配原则,默认匹配以test开头的文件名,星号表示后续的多个字符。
top_level_dir=None:测试模块的顶层目录,如果没有顶层目录,默认为None。
注意:
discover对给定的目录是有要求的,它Python的包,也就是目录有‘init.py’文件的才算是Python的包,只要是要读取的目录,都必须是包。
关于start_dir和top_level_dir的几种情况:
- start_dir目录可以单独指定,这个时候,让top_level_dir保持默认(None)即可。
- start_dir == top_level_dir, start_dir目录与top_level_dir目录一致,discover寻找start_dir指定目录内的符合规则的模块。
- start_dir < top_level_dir,start_dir目录是top_level_dir目录的子目录。discover寻找start_dir指定目录内的符合规则的模块。
- start_dir > top_level_dir,start_dir目录如果大于top_level_dir目录,等待你的是报错AssertionError: Path must be within the project。说你指定的路径(start_dir)必须位于项目内(top_level_dir)。
unittest中类级别的setup和tearDown
class myUnitTest(unittest.TestCase):
# def test_sub(self): # self.assertEqual(10-5, 5) def setUp(self): print('敌军还有三十秒到达战场, 碾碎他们....') def test_add(self): print(3333333333333333333) self.assertEqual(2+3, 5) def tearDown(self): # time.sleep(5) print('打完收工,阿sir出来洗地了.....') # @classmethod def setUpClass(cls): print('在用例集开始执行,我去建立数据库连接......') @classmethod def tearDownClass(cls): print('全军撤退, 我收工.......')
if name == 'main':
unittest.main()
verbosity参数
import unittest
class TestStringMethods(unittest.TestCase):
def test_assertFalse(self): self.assertFalse('')
if name == 'main':
unittest.main(verbosity=1)
0是静默模式,简单的输出结果
1,静默模式,添加每个用例执行的结果,通过是 . ,失败是 F,报错是 E
2,详细模式,详细的输出,详细的输出每个用例的执行结果
unittest.skip
跳过的提示‘s’.
使用实例:
import unittest
class TestCase01(unittest.TestCase):
@unittest.skip(reason='跳过') def test_case_01(self): self.assertTrue(1) @unittest.skipIf(condition=1, reason='条件为真跳过用例') def test_case_02(self): self.assertTrue(1)
if name == 'main':
unittest.main()
插件
unittest中的插件暂时不能使用pip
下载我们从网上下载:https://www.cnblogs.com/Neeo/articles/7942613.html