Python 教程-代码测试

file

测试你的代码是非常重要的。

习惯于同时写测试用例和运行代码,现在被视为一个好的习惯。如果使用得当,这种方式将帮助你更加明确自己代码的功能,以及拥有更加可解耦的结构。

测试的通用规则:

  • 测试单元应该集中于最小部分功能,并且证明它是正确的。
每个测试单元必须完全独立。他们都能够单独运行,也可以在测试套件中运行,而不用考虑被调用的顺序。 要想实现这个规则,测试单元应该加载最新的数据集,之后再做一些清理。 这通常用方法 setUp() 和 tearDown() 处理。 尽量使测试单元快速运行。如果一个单独的测试单元需要较长的时间去运行,开发进度将会延迟, 测试单元将不能如期常态性运行。有时候,因为测试单元需要复杂的数据结构, 并且当它运行时每次都要加载,所以其运行时间较长。请把运行速度较慢的测试单元放在单独的测试组件中, 并且按照需要运行其它测试单元。 学习使用工具,学习如何运行一个单独的测试或者测试用例。当为某个模块开发了一个新功能时, 我们需要经常运行这个功能的测试用例,理想情况下需配置工具让其在保存代码文件时自动触发运行测试。 在编码工作开始前后,请运行完整的测试组件。只有这样,你才会坚信现有的代码不会出现错误。 使用钩子(hook)是一个非常推荐的做法,一旦把代码提交到共享的代码仓库时(译者注:很多时候你会选择 Github), 即可触发钩子运行所有的测试。 如果你在开发期间不得不打断自己的工作,请先为你下一步要开发的功能写一个未通过的测试,这样当你回到工作时,将可以很快地回到原先被打断的地方,并且步入正轨。 当你调试代码的时候,首先需要写一个精确定位 Bug 的测试单元。尽管这样做很难, 但是捕捉 Bug 的单元测试在项目中很重要。


  • 测试函数需使用长且描述性的名字。测试的编码规范与代码编码规范有点不一样,代码更倾向于使用短的名字, 而测试函数不会直接被调用。在运行代码中,square() 或者甚至 sqr() 这样的命名都是可以的, 但是在测试代码中,您应该这样取名 test_square_of_number_2(),test_square_negative_number()。 当测试单元失败时,函数名会被直接显示出来,此时函数名称的描述性将变得重要。
当业务逻辑不得不变更时,如果代码中有一套不错的测试单元, 维护者将很大一部分依靠测试组件解决问题,或者确保改动不会影响到其他代码。此时测试代码会经常被阅读, 阅读的频率甚至多于业务逻辑代码。目的不明确的测试单元在这种情况下没有多少用处,因此请尽量避免书写目的不明确的测试代码。 测试代码的另外一个用处是作为新开发人员的入门介绍。当有人需要基于现有的代码库工作时, 运行并且阅读相关的测试代码是最好的做法。他们会或者应该发现业务代码的重点、难点、以及边界场景。 如果他们必须添加一些功能,第一步应该是添加一个测试,以确保新功能开发能保持测试的传统。


入门

Unittest 单元测试

unittest 是 Python 标准库中自带的测试模块。任何一个使用过 Junit,nUnit, 或 CppUnit 工具的人对它的 API 都会比较熟悉。

我们可以通过继承 unittest.TestCase 来创建测试用例:

import unittest

def fun(x):
return x + 1

class MyTest(unittest.TestCase):
def test(self):
self.assertEqual(fun(3), 4)

Python 2.7 以后,unittest 已支持测试自动发现机制。


关于 unittest 的标准库文档



Doctest


doctest 模块会在代码的 Docstrings 中寻找类似于 Python 交互会话的字串(译者注:>>>),并会将其执行,以证实工作正常。


Doctest 模块的使用场景与单元测试有所不同:它们通常不是很详细,并且不会用特别的用例或者处理复杂的 Bug。Doctest 主要是作为模块和其部件主要用例的表述性文档,因此,Doctest 需在每一次完整测试 套件运行时自动运行。


函数中的一个简单 Doctest 例子:


def square(x):
"""Return the square of x.

>>> square(2)
4
>>> square(-2)
4
"""

return x * x

if name == 'main':
import doctest
doctest.testmod()


当使用 python module.py 这样的命令行运行这个模块时,Doctest 将会运行,并会在结果与文档字符串的描述不一致时报错。


其他工具


py.test


相比于 Python 标准库里的 unittest 模块,py.test 也是一个没有模板(no-boilerplate)的备选方案:


$ pip install pytest


尽管这个测试工具功能完备,并且可扩展,它仍然能保持语法很简单。创建一个测试组件和写一个带有诸多函数的模块一样容易:


# content of test_sample.py
def func(x):
return x + 1

def test_answer():
assert func(3) == 5


运行命令 py.test :


$ py.test
=========================== test session starts ============================
platform darwin -- Python 2.7.1 -- pytest-2.2.1
collecting ... collected 1 items

testsample.py F

================================= FAILURES =================================
__
test_answer __

def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)

test_sample.py:5: AssertionError
========================= 1 failed in 0.02 seconds =========================


可以看出,这要比 unittest 模块中实现相同功能所要求的工作量少得多。



py.test



Hypothesis


Hypothesis 让你编写被示例源码参数化的测试库。它会生成简单易懂的例子,使你的测试失败, 让你花更少的力气找到更多的错误。


$ pip install hypothesis


例如,测试浮动列表要尝试很多例子,但是会报告每个错误的最小例子(区分异常类型和位置):


@given(lists(floats(allow_nan=False, allow_infinity=False), min_size=1))
def test_mean(xs):
mean = sum(xs) / len(xs)
assert min(xs) <= mean(xs) <= max(xs)


Falsifying example: test_mean(
xs=[1.7976321109618856e+308, 6.102390043022755e+303]
)


Hypothesis 是实用且强大的工具,很多时候它都会找出被其他测试工具所遗漏的错误。 它能与 py.test 很好地集成,无论是简单亦或者是高级场景中,你都会觉得它很趁手。



hypothesis



tox


tox 是一个自动化测试环境管理,并能针对多版本解释器配置进行测试的工具。


$ pip install tox


tox 允许你通过简单的配置文件,来设置复杂的多参数测试矩阵。



tox



Unittest2


Unittest2 是 Python 2.7 中 unittest 模块的向后兼容补丁,对比 Python 2.7 之前的版本提供了更好的 API 和断言语法。


如果使用 Python 2.6 版本或者以下,你可以使用 pip 安装 unittest2:


$ pip install unittest2


推荐你使用 unittest 之名导入模块,目的是更容易地把代码移植到新的版本中:


import unittest2 as unittest

class MyTest(unittest.TestCase):
...


如果切换到新的 Python 版本,并且不再需要 unittest2 模块,你只需要在测试模块中改变 import 内容,而不必改变其它代码。



unittest2



mock


unittest.mock 是 Python 中用于测试的一个库。 Python 3.3 版本中,将存在于自带的标准库中 —— 标准库中的 unittest.mock


对于 Python 相对早的版本,如下操作:


$ pip install mock


在测试环境下,使用 mock 对象能够替换部分系统,并且对它们的使用进行断言。


例如,你可以对一个方法打猴子补丁:


from mock import MagicMock
thing = ProductionClass()
thing.method = MagicMock(return_value=3)
thing.method(3, 4, 5, key='value')

thing.method.assert_called_with(3, 4, 5, key='value')


在测试环境下,你可以使用 patch 修饰器来 mock 某个模块中的类或对象。在下面这个例子中,一直返回相同结果的外部查询系统使用 mock 替换(但仅用在测试期间)。


def mock_search(self):
class MockSearchQuerySet(SearchQuerySet):
def iter(self):
return iter(["foo", "bar", "baz"])
return MockSearchQuerySet()

# 这里的 SearchForm 指的是 myapp 引入的类,
# 而不是类 SearchForm 本身自己
@mock.patch('myapp.SearchForm.search', mock_search)
def test_new_watchlist_activities(self):
# get_search_results 运行一次搜索并对结果进行迭代
self.assertEqual(len(myapp.get_search_results(q="fish")), 3)


Mock 还提供许多其它方法,你可以很轻松地配置和控制它的行为。



Mock 的文档


Image placeholder
qingqi
未设置
  1人点赞

没有讨论,发表一下自己的看法吧

推荐文章
【python测试开发栈】帮你总结python random模块高频使用方法

随机数据在平时写python脚本时会经常被用到,比如随机生成0和1来控制逻辑、或者从列表中随机选择一个元素(其实抽奖程序也类似,就是从公司所有人中随机选择中奖用户)等等。这篇文章,就帮大家整理在pyt

【python测试开发栈】帮你总结python time模块高频使用方法

在平时写python脚本时,时间是我们经常用到的数据,比如:时间戳、前端展示的对应格式的时间等,在python中主要有三个和时间处理相关的模块:time、datetime、calendar,这篇文章主

Python 教程-了解Python

什么是Python Python能干什么? 有什么特点? 什么是Python 官方介绍: Python是一个易于学习、功能强大的编程语言。它拥有高效高级的数据结构和一种简单有效的面向对象编程的

Python 教程-Python 安装

在Windows上安装 访问https://www.python.org/downloads/并下载最新版本。在撰写时当前最新是3.8。在安装的时候和其他软件一样,无脑式下一步。需要注意的是如果在W

Python入门教程_2. 使用 Python 解释器

2.1.调用解释器 Python解释器通常安装在目标机器上的/usr/local/bin/python3.7目录下;把/usr/local/bin目录放进你的Unixshell的搜索路径里,确保它可以

Python入门教程_3. Python 简介

在下面的例子中,输入和输出分别由大于号和句号提示符(>>>和...)标注:如果想重现这些例子,就要在解释器的提示符后,输入(提示符后面的)那些不包含提示符的代码行。需要注意的是在练习中遇到的从属提示符

Python入门教程_4. 深入 Python 流程控制

除了刚刚介绍的while语句,Python还有一些在其他语言中常见的控制流语句,并做了一些改动。 4.1.if语句 也许最著名的语句是if语句了。 例如: >>>x=int(input("Please

流畅的Python读书笔记 --- 第一章 Python数据模型

近期开始读“流畅的Python”这本书,想把自己的读书笔记分享给大家,希望能帮到也对这本书感兴趣但是没时间看的各位。(文章中大部分的话和图片摘录总结自“流畅的Python”一书,以及python官方网

面向回家编程!GitHub标星两万的”Python抢票教程”,我们先帮你跑了一遍

盼望着,盼望着,春节的脚步近了,然而,每年到这个时候,最难的,莫过于一张回家的火车票。据悉,今年春运期间,全国铁路发送旅客人次同比将增长8.0%。达到4.4亿人次,2020年铁路春运自1月10日开始,

SWIG-Python中调用C代码的另一种方法

SWIG SWIG是SimplifiedWrapperandInterfaceGenerator的缩写。是Python中调用C代码的另一种方法。在这个方法中,开发人员必须编写一个额外的接口文件来作为S

1000 行 Python 代码脚本 bug,或影响上百篇学术论文

《Nature》杂志2014年的一篇论文包含了一个Python脚本,其中有一个模块是根据文件的排序返回值,但Python并没有定义查询的文件顺序。这意味着在不同的操作系统上,该脚本返回的值是不同的。

教你阅读 Python 开源项目代码

为什么要阅读开源代码 阅读Python开源项目代码主要有如下三个原因: 在工作过程中遇到一些问题Google和StackOverFlow等网站找不到解决办法,只能去翻源码。 对某些项目或者方向非常感

56岁潘石屹下决心学Python,60岁程序语言之父们还在敲代码,你呢

比你成功的人,比你还努力。上周,SOHO中国董事长、地产大亨 潘石屹,56岁生日当天发布微博宣布进军编程语言Python。 紧接着第二天,又更新微博解释为何会做出此举。潘石屹给出的解释大致就是,在不断

Python 教程-从变量开始

先认识一下计算机 主要分为五个部分:控制器,运算器,存储器,输入设备,输出设备。输入输出设备大家都比较熟悉,最常见的输入设备比如鼠标、键盘、扫描仪等,输出设备比如,显示器、打印机、音响等。主要说一下

Python教程-强制数据类型转换

数据类型转换分为两种,一种是自动数据类型转换(隐式)和强制数据类型转换(显式)原则上不同的数据之间无法进行运算,自动数据类型转换是程序自发的行为,比如在运算时(或判断时)。在需要的情况下进行的操作

Python 教程-机器学习

Python有着海量的可用于数据分析、统计以及机器学习的库,这使得Python成为很多数据科学家所选择的语言。 下面我们列出了一些被广泛使用的机器学习及其他数据科学应用的Python包。

Python教程-一文读懂运算和运算符

Python支持多种运算符,下表按照优先级从高到低的顺序列出了所有的运算符,运算符的优先级指的是多个运算符同时出现时,先做什么运算然后再做什么运算。 [][:] 下标,切片 ** 指数 ~+- 按

Python 教程-分支结构

应用场景 迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种代码结构通常称之为顺序结构。然而顺序结构并不能解决所有的问题,比如我们在设计学习猿地学习系统的时候,我们设计成关卡制,每一关需

Python入门教程_1. 开胃菜

如果你在计算机上做大量的工作,最终你会发现你想要可以自动完成一些任务。例如,你可能希望对大量文本文件执行搜索和替换,或者以复杂的方式重命名和重新排列一堆照片文件。又或许你想编写一个小型自定义数据库,或

Python入门教程_5. 数据结构

这个章节将更详细地描述一些你已经了解的内容,并且添加了一些新的内容。 5.1.深入列表对象 List数据类型包含更多的方法,下面是List对象包含的所有方法: list.append(*x*) 将一个

Python入门教程_6. 模块

如果你从Python解释器退出然后再进入它,你所做的定义(函数和变量)都会消失。因此,如果你想写某些更长的程序,你最好使用一个文本编辑器来为解释器准备输入,然后以这个文件作为输入来运行程序。这也被称为

Python教程-循环结构

在Python中构造循环结构有两种做法,一种是for-in循环,一种是while循环。再程序中循环经常用到,比如在展示文章或者商品列表的时候,我们循环数据,并且转成html格式,我们需要对循环非常

Python入门教程_7. 输入和输出

程序的输出可以有多种形式:我们可以将数据以人类可读的形式打印到屏幕上,或者将其写入到文件中以供后续使用。本章将讨论其中的几种实现方式。 7.1.格式化输出 迄今为止,在Python中存在两种输出值的方

Python教程-函数

函数就是一个具有特定功能的语法结构。是一系列代码的组合,为实现一个具体的功能,比如print打印字符。函数的主要作用是提高代码的复用率,提高开发效率,减少后期的维护成本。在实际开发中一般我们遵守单一

Python教程-将序列分解为单独的变量

问题 现在有一个包含N个元素的元组或者是序列,怎样将它里面的值解压后同时赋值给N个变量? 解决方案 任何的序列(或者是可迭代对象)可以通过一个简单的赋值操作来分解为单独的变量。唯一的要求就是变量的总数