目录:

1.unittest.TestCase中常用的断言方法

  1.1 subTest子测试

  1.2 套件测试

  1.3 批量测试单个用例

2. 加载器

  2.1加载器协议

  2.2.执行器 TestRunner

3.已现成的测试函数用例

4.Mock

Mock对象的参数:

  4.1 return_value

  4.2 side_effect

  4.3 spec

  4.4 wraps

MagicMock对象额外方法

  4.5mock_add_spec方法

5. patch 用模拟对象替换真实对象

6.代码覆盖率coverage


1. unittest.TestCase类中的常用的断言方法

方法 用途
assertEqual(a, b) 核实 a == b
assertNotEqual(a, b) 核实 a != b
assertTrue(x) 核实 x 为True
assertFalse(x) 核实 x 为False
assertIn(itemlist) 核实itemlist
assertNotIn(itemlist) 核实item不在list

1.1 子测试:记录错误并测试完所有的代码

class DemoTest(unittest.TestCase):
def test_subtest(self):
for i in range(5):
with self.subTest(name=i): # 子测试参数用于输出
self.assertEqual(i % 2, 0) >>>
(djProj_py3) appledeMacBook-Air-7:tests apple$ python -m unittest test_a.DemoTest.test_subtest ======================================================================
FAIL: test_subtest (test_a.DemoTest) (name=1)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/apple/PycharmProjects/work/practice/tests/test_a.py", line 19, in test_subtest
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0 ======================================================================
FAIL: test_subtest (test_a.DemoTest) (name=3)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/apple/PycharmProjects/work/practice/tests/test_a.py", line 19, in test_subtest
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0 ----------------------------------------------------------------------
Ran 1 test in 0.000s FAILED (failures=2)

1.2测试套件:将多个用例或套件的实例组合起来,完成产品功能组级别的测试。

分别为每个参与测试方法创建实例,并加入套件。

class UserTest(unittest.TestCase):

    def test_user(self):
self.assertTrue(True) # 判断是否为真 class CartTest(unittest.TestCase): def test_cart(self):
self.assertFalse(False) suite = unittest.TestSuite()
suite.addTests((UserTest('test_user'), # 创建实例并加入套件suite
CartTest('test_cart'),)
)
unittest.TextTestRunner(verbosity=2).run(suite) # TextTestRunner执行器

# code end!!
>>>
(djProj_py3) appledeMacBook-Air-7:tests apple$ python test_a.py
test_user (__main__.UserTest) ... ok
test_cart (__main__.CartTest) ... ok ----------------------------------------------------------------------
Ran 2 tests in 0.000s OK

1.3 批量测试单个用例,可通过重写runTest

class TestDamo(unittest.TestCase):
def add(self):
self.assertTrue(1) def add1(self):
self.assertFalse('') def runTest(self):
tests = (self.add, self.add1)
for test in tests:
with self.subTest(t=test):
test() >>>
(djProj_py3) appledeMacBook-Air-7:tests apple$ python -m unittest -v test_a.py
runTest (test_a.TestDamo) ... ok ----------------------------------------------------------------------
Ran 1 test in 0.000s OK

2.加载器

完整的流程是:1.discover递归目录,查找所有文件名相符的模块。loadTestsFromModule 在模块内获取所有的用例类型,再通过以loadTestsFromTestCase

为用例的全部测试方法创建实例。最终,将之组合成测试套件交给执行器。

注: loadTestsFromTestCase调用了getTestCaseNames查找类型中包含 特定前缀(test)的测试方法,无则选择runTest;

  loadTestsFromModule按照加载协议(load_tests),先调用load_tests函数返回自定义测试套件。仅在没有协议实现时,才返回所用的用例类型;

   可以自己创建加载器对象或使用默认的defaultTestLoader实例。

class TestDamo(unittest.TestCase):
def test_add(self):
self.assertTrue(1) def test_add1(self):
self.assertFalse('') def runTest(self):
self.assertFalse('a') class Test1Damo(unittest.TestCase):
def runTest(self):
self.assertFalse('')
loader = unittest.defaultTestLoader
a = loader.loadTestsFromTestCase(TestDamo)
print(a)
b = loader.loadTestsFromModule(sys.modules[__name__])
print(b) >>>
(djProj_py3) appledeMacBook-Air-7:tests apple$ python test_a.py <unittest.suite.TestSuite tests=[<__main__.TestDamo testMethod=test_add>, <__main__.TestDamo testMethod=test_add1>]>
<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<__main__.Test1Damo testMethod=runTest>]>,
                    <unittest.suite.TestSuite tests=[<__main__.TestDamo testMethod=test_add>,
                                        <__main__.TestDamo testMethod=test_add1>]>
]>
# 2.1改写加载器协议
def load_tests(loader, standard_tests, pattern):
suite = unittest.TestSuite()
suite.addTests(map(TestDamo, ('test_add', 'test_add1')))
return suiteb = loader.loadTestsFromModule(sys.modules[__name__])
b = loader.loadTestsFromModule(sys.modules[__name__])
print(b)
>>> (djProj_py3) appledeMacBook-Air-7:tests apple$ python test_a.py 
# 改写加载器协议后,只加载了协议指定TestDamo用例
<unittest.suite.TestSuite tests=[<__main__.TestDamo testMethod=test_add>, <__main__.TestDamo testMethod=test_add1>]>
 

2.2.执行器TestTunner

用于接受用例或套件,执行测试并返回结果

3.已现成的测试函数用例

用FunctionTestCase包装,它本身是继承的unittest.TestCase

def test():
assert False result = unittest.FunctionTestCase(test).run()
print(result.failures) >>>
(djProj_py3) appledeMacBook-Air-7:tests apple$ python test_a.py
[(<unittest.case.FunctionTestCase tec=<function test at 0x10cc62bf8>>,
'Traceback (most recent call last):\n File "test_a.py", line 99, in test\n assert False\nAssertionError\n')]

4.Mock

Mock以__getattr__拦截被mock替换对象的属性访问,动态创建‘替换对象成员’。 且新建成员同是模拟类型,以实现链式属性设置和访问。

我对mock的理解:测试对象功能尚未完成或者依赖其他环境(例如db),可用mock替换该测试对象并指定返回结果。其作用:先完成测试逻辑,

接触开发次序依赖

4.1 return_value

设置测试对象的返回值

>>> import unittest
>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.func.return_value = 1
>>> import unittest
>>> from unittest.mock import Mock
>>> m = Mock()
>>> def func(a, b):return a+b
...
>>> m.func.return_value = 99
>>> func(50, 50)
100
>>> m.func(50, 50)
99
>>> m.func(50, 50, 1)
99
结论:通过Mock对象指定测试用例返回值后,再通过Mock调用测试对象,并不会去执行而是直接返回return_value的值

4.2 side_effect

构造参数side_effect指定可调用对象,迭代器,异常。用来替代return_value返回

# side_effect指定为可调用对象
>>> m = Mock(side_effect=lambda x: x+10)
>>> m(1)
11 # side_effect指定迭代器
>>> m = Mock()
>>> m.next = Mock(side_effect=[1,2,3])
>>> m.next
<Mock name='mock.next' id=''>
>>> m.next()
1
>>> m.next()
2
>>> m.next()
3
>>> m.next()
StopIteration # side_effect指定为异常
>>> m.next = Mock(side_effect=KeyError('key error'))
>>> m.test = Mock(side_effect=KeyError('key error'))
>>> m.test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
raise effect
KeyError: 'key error' # side_effect的可调用对象返回值为unittest.mock.DEFAULT时,实际返回值为return_value的值
>>> m = Mock(side_effect=lambda x: 100 if x>0 else unittest.mock.DEFAULT, return_value=99)
>>> m(1)
100
>>> m(0)
99
# side_effect设置为None时,返回值为return_value
>>> m.side_effect = None
>>> m(1)
99

4.3 spec

可从列表 或 某个类型提取属性名字,用以约束模拟对象mock。

# 从列表提取属性名字
>>> m = Mock(spec=['a', 'b'])
>>> m.a
<Mock name='mock.a' id=''>
>>> m.b
<Mock name='mock.b' id=''>
>>> m.c
AttributeError: Mock object has no attribute 'c' # 从类提取属性名字
>>> class A:
... a = 1
... def b(self):
... return 2
...
>>> m = Mock(spec=A)
>>> m.a
<Mock name='mock.a' id=''>
>>> m.b
<Mock name='mock.b' id=''>
>>> m.c
AttributeError: Mock object has no attribute 'c'
# spec参数并不能阻止通过赋值创建属性
>>> m.c = 3 # 创建成功
>>> m.c
3 # spec_set可以阻止赋值创建属性
>>> m = Mock(spec_set=['a'])
>>> m.a
<Mock name='mock.a' id=''>
>>> m.b
AttributeError: Mock object has no attribute 'b'
>>> m.b = 3 # 创建失败
AttributeError: Mock object has no attribute 'b' # create_autospec约束参数列表,使mock模拟的对象与测试对象参数一致
>>> m = unittest.mock.create_autospec(A, spec_set=True, instance=True)
>>> m.test()
TypeError: missing a required argument: 'a'
>>> m.test(a=1)
TypeError: missing a required argument: 'b'
>>> m.test(a=1,b=2)
<MagicMock name='mock.test()' id=''>
>>> m.test.return_value = 1 # 指定模拟对象的返回值
>>> m.test(1,2)
1 # 从lambda对象中提取参数,限制模拟对象m.test
>>> m = Mock()
>>> m.test = unittest.mock.create_autospec(lambda a,b: 2, return_value=1) # 从lambda中提取参数a, b
>>> m.test(1)
>>> m.test = unittest.mock.create_autospec(lambda a,b: 2, return_value=1)
>>> m.test(1,2)
TypeError: missing a required argument: 'b'
>>> m.test(1,2)
1

4.4 wraps参数

可以将模拟对象的访问传值传递给真是对象, 这样可以在模拟和真实对象间切换,而非删除代码

>>> class A:
... def add(self, a, b):return a+b
>>> m = Mock(spec_set=A, wraps=A())
>>> m.add(50, 50)
100
# 但是一旦设置return_value,则不再传递参数给真实对象
>>> m.add.return_value=99
>>> m.add(50, 50)
99

4.5 MagicMock

额外提供mock_add_spec方法,用于调整spec设置

# 重置spec_set的参数(True:spec_set, False:spec)
>>> m.mock_add_spec(['a'], True)
# 阻止所有属性的访问 = Mock(spec_set=[])
>>> m.mock_add_spec([], True)
# 取消spec or spec_set设置
>>> m.mock_add_spec(None)

5. patch

使用patch将真实对象替换成模拟的对象(真是对象 x + y, 模拟对象 a去替换真实对象x,变成 a + y)

测试用例为:

test_a.py

from unittest.mock import patch
import requests def logic(url):
data = requests.get(url=url)
return data.status_code

5.1 patch 上下文管理器用法

class DemoTest(unittest.TestCase):
def test_1(self):
# 设置固定数据
data = SimpleNamespace(url='https://www.baidu.com', code=200)
with patch("test_a.logic", lambda url: data.code) as m: # 将test_a.py下的logic方法 用 lambda去替换。
self.assertEqual(m(data.url), data.code) (djProj_py3) appledeMacBook-Air-7:tests apple$ python -m unittest -v test_a.py
test_1 (test_a.DemoTest) ... ok ----------------------------------------------------------------------
Ran 1 test in 0.000s OK

5.2 patch 装饰器用法

  5.2.1 @patch('requests.get')  替换为 get (get自己起的名字)

class DemoTest(unittest.TestCase):
@patch('requests.get')
def test_1(self, get):
data = SimpleNamespace(url='https://www.baidu.com', code=200)
get.return_value.status_code = data.code
self.assertEqual(logic(data.url), data.code) (djProj_py3) appledeMacBook-Air-7:tests apple$ python -m unittest -v test_a.py
test_1 (test_a.DemoTest) ... ok ----------------------------------------------------------------------
Ran 1 test in 0.001s OK

 5.2.2  将test_a.logic替换成 lambda url: 200

class DemoTest(unittest.TestCase):
@patch('test_a.logic', lambda url: 200) # arg: url, return_value: 200
def test_1(self):
data = SimpleNamespace(url='https://www.baidu.com', code=200)
self.assertEqual(logic(data.url), data.code) (djProj_py3) appledeMacBook-Air-7:tests apple$ python -m unittest -v test_a.py
test_1 (test_a.DemoTest) ... ok ----------------------------------------------------------------------
Ran 1 test in 0.000s OK

6.coverage代码覆盖率  pip install coverage

pip install coverage

(djProj_py3) appledeMacBook-Air-7:tests apple$ coverage run --source . -m unittest test_a.DemoTest  # 仅测试当前目录下的文件
.
----------------------------------------------------------------------
Ran 1 test in 0.000s OK
(djProj_py3) appledeMacBook-Air-7:tests apple$ coverage report # 测试结果生成文本
(djProj_py3) appledeMacBook-Air-7:tests apple$ coverage html  # 测试结果生成HTML文件

python-单元测试unittest的更多相关文章

  1. python单元测试unittest

    单元测试作为任何语言的开发者都应该是必要的,因为时隔数月后再回来调试自己的复杂程序时,其实也是很崩溃的事情.虽然会很快熟悉内容,但是修改和 调试将是一件痛苦的事情,如果你在修改了代码后出现问题的话,而 ...

  2. [转]python单元测试unittest

    单元测试作为任何语言的开发者都应该是必要的,因为时隔数月后再回来调试自己的复杂程序时,其实也是很崩溃的事情.虽然会很快熟悉内容,但是修改和调试将是一件痛苦的事情,如果你在修改了代码后出现问题的话,而单 ...

  3. Python单元测试unittest - 单元测试框架

    一.unittest简介 unitest单元测试框架最初是有JUnit的启发,它支持测试自动化,共享测试的设置和关闭代码,将测试聚合到集合中,以及测试与报告框架的独立性. 二.unittest相关概念 ...

  4. python单元测试unittest实例详解

    转自:http://blog.csdn.net/five3/article/details/7104466 单元测试作为任何语言的开发者都应该是必要的,因为时隔数月后再回来调试自己的复杂程序时,其实也 ...

  5. python单元测试unittest、setUp、tearDown()

    单元测试反应的是一种以测试为驱动的开发模式,最大的好处就是保证一个程序模块的行为符合我们设计的测试用例,在将来修改的时候,可以极大程度保证该模块行为仍然是正确的. 下面我编写一个Dict来,这个类的行 ...

  6. Python单元测试unittest【转自https://www.cnblogs.com/feng0815/p/8045850.html】

    [转自https://www.cnblogs.com/feng0815/p/8045850.html] Python中有一个自带的单元测试框架是unittest模块,用它来做单元测试,它里面封装好了一 ...

  7. Python单元测试--unittest(一)

    unittest模块是Python中自带的一个单元测试模块,我们可以用来做代码级的单元测试. 在unittest模块中,我们主要用到的有四个子模块,他们分别是: 1)TestCase:用来写编写逐条的 ...

  8. selenium自动化测试、Python单元测试unittest框架以及测试报告和日志输出

    部分内容来自:https://www.cnblogs.com/klb561/p/8858122.html 一.基础介绍 核心概念:test case, testsuite, TestLoder,Tex ...

  9. python单元测试-unittest

    python内部自带了一个单元测试的模块,pyUnit也就是我们说的:unittest 1.介绍下unittest的基本使用方法: 1)import unittest 2)定义一个继承自unittes ...

  10. Python单元测试unittest测试框架

    本文的主题是自动化测试框架的实现,在实现之前,先了解一下关于unittest模块的相关知识: Python中有一个自带的单元测试框架是unittest模块,用它来做单元测试,它里面封装好了一些校验返回 ...

随机推荐

  1. Eclipse安装插件的“最好方法”:dropins文件夹的妙用

    在Eclipse3.4以前安装插件非常繁琐. 在Eclipse3.5以后插件安装的功能做了改进.而且非常方便易用. 我们只需要把需要的插件复制(拖放)到eclipse\dropins,然后插件就安装成 ...

  2. 响应json去除参数值为空的参数-springboot配置

    1.添加jackson相关依赖 <!--jackson 开始--><dependency> <groupId>com.fasterxml.jackson.core& ...

  3. Video to SDI Tx Bridge模块video_data(SD-SDI)处理过程

    Video to SDI Tx Bridge模块video_data(SD-SDI)处理过程 1.Top Level Block Diagram of Video to SDI TX Bridge V ...

  4. Python Flask 构建微电影视频网站

    前言 学完本教程,你将掌握: 1.学会使用整形.浮点型.路径型.字符串型正则表达式路由转化器 2.学会使用post与get请求.上传文件.cookie获取与相应.404处理 3.学会适应模板自动转义. ...

  5. 黄聪:wordpress如何获取访问的网站的cookie值

    $head = wp_get_http_headers( $word_url ); $cookie = $head['set-cookie']; $cookie = substr( $cookie, ...

  6. Hadoop 管理工具HUE配置-hdfs_clusters配置

    在HUE的hdfs_clusters中目前主要是配置hdfs相关的,配置好了之后便可以在hue中愉快的管理数据了,不过目前的配置还是比较...简单的..    里面的配置主要是参考了hue官方文档,还 ...

  7. go语言学习--go的临时对象池--sync.Pool

    一个sync.Pool对象就是一组临时对象的集合.Pool是协程安全的. Pool用于存储那些被分配了但是没有被使用,而未来可能会使用的值,以减小垃圾回收的压力.一个比较好的例子是fmt包,fmt包总 ...

  8. windows server 2008 R2 安装

    微软服务器操作系统大致有: server 2000(简称2K),还有server 2003(2K3),server 2008(2K8),server 2000和2003是基于NT内核的,而2008是基 ...

  9. 浅析Linux DeviceTree

    文本将介绍Linux DeviceTree的相关知识,包括DeviceTree源文件.结构.语法.编写规则等. DeviceTree基础 DeviceTree(以下简称DT)用于描述设备信息以及设备于 ...

  10. linux system()函数详解

    system(3) - Linux man page Name system - execute a shell command Synopsis #include <stdlib.h> ...