最近看了 Axb的自我修养 写的关于好代码,烂代码和单元测试的一些文章,挺受启发的,结合python讲一下自己对单元测试的理解和操作。
单元测试是什么单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
为什么要进行单元测试?笔者最近接手公司项目发现之前是一行测试代码都没有的,其实自己以前也不是很了解单元测试的东西。但是感觉既然是公司的正规项目,就得有质量和流程上的保证,写一些单元测试还是必要的。但是我们不是为了测试而测试,我觉得测试除了保证程序的健壮性外,是可以让你重新思考代码的设计的。引用Axb博客的话:
编写单元测试的难易程度能够直接反应出代码的设计水平,能写出单元测试和写不出单元测试之间体现了编程能力上的巨大的鸿沟。无论是什么样的程序员,坚持编写一段时间的单元测试之后,都会明显感受到代码设计能力的巨大提升。如果发现代码难以构造测试,很有可能就是接口设计不够优雅,或者耦合严重,尝试从测试的角度思考能够让我们更好地设计。单元测试同时也为重构提供了保证,比如我们想优化一个函数内部实现,更换更优的数据结构和算法,只需要重新跑一下测试就可以验证新的实现是否引入了错误或bug。
总的来说,单元测试有以下好处:
确保代码质量 改善代码设计,难以测试的代码一般是设计不够简洁的代码。 保证重构不会引入新问题,以函数为单位进行重构的时候,只需要重新跑测试就基本可以保证重构没引入新问题。 测试如何影响代码设计


以上来自《编写可读代码的艺术》,需要自己实践才有体会。
python测试相关库 unittest,内置库,模仿PyUnit写的,简洁易用,缺点是比较繁琐。 pytest,笔者目前喜欢用这个,写起来很方便。 nose,测试发现,发现并运行测试。 使用pytest进行python进行单元测试python内置了一个 unittest ,但是写起来稍微繁琐,比如都要写一个TestCase类,还得用 assertEqual, assertNotEqual等断言方法。 而使用pytest运行测试统一用assert语句就行,兼容unittest,目前很多知名开源项目如PyPy,Sentry也都在用。关于pytest的使用可以参考其官方文档,虽然有很多高级特性,但是掌握其中一小部分基本就够用了。
下面是py.test的基本用法,以常见的两种测试类型(验证返回值和抛出异常)为例:
def add(a, b): """return a + b Args: a (int): int b (int): int Returns: a + b Raises: AssertionError: if a or b is not integer """ assert all([isinstance(a, int), isinstance(b, int)]) return a + b def test_add(): assert add(1, 2) == 3 assert isinstance(add(1, 2) , int) with pytest.raises(Exception): # test exception add('1', 2)这是个脑残示例,不过基本使用就是这么简单。真实场景下远远比这个复杂,甚至有时候构造测试的时间比写业务逻辑的时间还要长。但是再复杂的逻辑也是一点点功能堆积,如果可以确保每一部分都正确,整体上是不会出错的。单元测试同时也提醒我们,函数完成的功能尽可能单一,这样才利于测试。
下面几个是我常用的pytest命令:
py.test test_mod.py # run tests in module py.test somepath # run all tests below somepath py.test -q test_file_name.py # quite输出 py.test -s test_file_name.py # -s参数可以打印测试代码中的输出,默认不打印,print没结果 py.test test_mod.py::test_func # only run tests that match the "node ID", py.test test_mod.py::TestClass::test_method # run a single method in 测试驱动开发(TDD)的流程为了实现一个函数,很多人的流程是这样的:
匆匆写代码->实现后print输出看结果->有逻辑或语法错误->修改->继续print输出看结果
循环往复。
采用TDD的流程如下:

当然也不用完全采用tdd,先写测试有时候很繁琐,但是对于比较重要的api函数,最好还是要有单元测试。为了使项目质量得到保证,TDD中的一些思想还是值得借鉴的。很多东西也在摸索,推荐学习下flask,requests等开源项目的单元测试代码,以后再慢慢更新吧。
参考关于烂代码的那些事
使用Spock框架进行单元测试
Beginning Test-Driven Development in Python
【Pytest】python单元测试框架pytest简介