目录:

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. Qt 中的事件处理(一)

    1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的 系统内核的消息通过事件处理转变成QT的信号 2. Qt中 ...

  2. .net 读取/保存 文件 到 局域网 服务器

    public class IdentityScope : IDisposable { /// <summary> /// 登录一个新用户 /// </summary> /// ...

  3. VSFTP再配置 我里个去马蛋网上这么多烂文章,走了好多弯路

    1.CentOS 进行yum 安装 vsftpd 2.vi /etc/vsftpd/vsftpd.conf  进行配置 3.创建FTP 用户 # useradd –d /var/www -g ftp ...

  4. Requests+正则表达式爬取猫眼电影

    目标 提取出猫眼电影TOP100的电影名称.时间.评分.图片等信息,提取站点的URL为http://maoyan.com/board/4,提取的结果以文本的形式保存下来. 准备工作 请安装好reque ...

  5. DS图遍历--深度优先搜索

    DS图遍历--深度优先搜索 题目描述 给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始 注意:图n个顶点编号从0到n-1 代码框架如下: 输入 第一行输入t,表示有t个测试实例 第二行输入n, ...

  6. VBA Dumper v0.1.4.2, 提取office文档中的VBA代码,监查宏病毒恢复代码(演示版

    http://club.excelhome.net/thread-970051-1-1.html VBA Dumper 0.1.4.2更新,填补国内同类程序空白 此程序为演示版,可以在无office的 ...

  7. problem:为什么会有options请求

    为了安全考虑,浏览器对资源访问有同源限制的问题,也就是web应用程序只能访问和它同一协议同一域名同一端口的web应用程序上的资源. 通过跨域资源共享机制可以让资源在浏览器中访问与该资源本身不同域的资源 ...

  8. IIS性能优化篇

    首先程序的优化,不只是沿着一个点进行,往往都是程序配合服务器及数据服务器配置提升性能. 第一步:数据库链接优化 在数据库链接字符串中添加“Max Pool Size=32767;”,32767是数据库 ...

  9. scroll家族属性

    上一篇主要分析了一下offset家族属性,本篇文章则主要是来分析一下scroll家族属性. 首先,scroll家族包括4个属性: 网页正文宽度:document.body.scrollWidth; 网 ...

  10. Scala传名参数(By-Name)

    1.=> 在了解Scala的By-Name参数之前,先了解下“=>”在Scala中有几种用法: 1.对于值,“=>”相当于lambda表达式.如: scala> List(,, ...