量化投资学习笔记179——测试驱动开发笔记

参考《Crafting Test-Driven Software with Python Write test suites that scale with your applications needs and complexity, using Python and PyTest》 Alessandro Molina著
使用python标准库自带的unittest库,

1
2
3
4
5
6
7
8
9
10
import unittest


class MyTestCase(unittest.TestCase):
def test_one(self):
pass


if __name__ == "__main__":
unittest.main()

unittest.main()会寻找unittest.TestCase的子类,并将test_开头的成员函数作为测试用例。可以同时建立很多测试。同一个测试里可以有多个用例。最好假设测试是随机执行的。可以将测试分布在不同文件,用unittest discover模式寻找一个目录下的测试。可以用-k选项寻找特定名称的测试执行。
每个测试用例按照条件-动作-验证的顺序写,条件是进行测试动作前的准备,然后进行测试动作,最后验证结果。条件往往包含在所调用的函数里,不需要单独写。
测试驱动开发,在实现代码以前写测试,迫使我们明确自己的需求。写完测试,测试失败,再实现代码,使测试通过。接着就可以重构修改代码了。如此反复更替。
单元测试的大小,取决于测试对象,一般为单个函数或类。在某些执行多个任务的类,可以分割成多个单元测试对象。单元是最小的可测试程序组成。
集成测试是对两个及以上模块进行测试。包括函数测试、端到端测试、系统测试、接收测试等。
实现TDD有自顶向下和自底向上两种方法。test double是用来替代我们程序中尚未完成、不完整的或昂贵的部分进行测试的对象。
当开发一个新功能时,第一步是写一个主要接受度测试(acceptance test),它可以帮助你明确定义自己想要达到的目标。
另一个测试库,pytest。与unittest最大的区别是它不用继承一个测试类,而是寻找任何名称包含有test的模块。也可以编辑项目下的文件pytest.ini来改变。
其判断语句为assert。
用-v选项显示详细信息。
用-k选项指定运行特定的测试,如-k first。其中first为特定测试函数所包含的名称。
unittest与pytest最大不同是pytest将测试与测试夹具(test fixture)解偶。这主要通过pytest.fixture装饰器实现。任何加了这个装饰器的函数就变成测试夹具,然后在测试模块中使用@pytest.mark.usefixtures装饰器来使用夹具。默认情况pytest会拦截所有程序输出,在执行pytest时加选项-s来输出。
可以使用多个测试夹具。别把测试夹具放在离使用它的地方太远的地方。测试夹具不但可以用于函数,也能用于类。可以设定夹具的scope为整个session并且autouse为True。
pytest还提供了tmp_path,每次运行测试提供了不同的临时路径。capsys夹具,用于捕捉标准输出。
pytest有两个配置文件,pytest.ini用于配置pytest本身,congtest.py用于配置测试用例。
pytest.mark.parametrize可以用来进行多参数测试。

再看看原始来源:《测试驱动开发》kent Beck著
测试驱动开发的口号:不可运行/可运行/重构。
测试驱动开发的步骤:

  1. 快速新增一个测试。
  2. 运行所有的测试,发现最新的测试不能通过。
  3. 做一些小小的改动。
  4. 运行所有测试,并且全部通过。
  5. 重构代码,以消除重复设计,优化结构。

程序出现依赖关系,其表现就是重复设计。
尽快使测试程序可运行的策略:

  1. 伪实现:返回一个常量并逐渐用变量代替常量,直至其成为真实实现的代码。
  2. 显明实现:将真实的实现代码键入。
  3. 三角法:当例子达到两个或更多时,才考虑对代码实施一般化。仅在完全不知道如何重构的情况下才使用。

当代码有重复时,考虑抽象出公共部分形成父类,再由子类继承。
除非有更好的动机,否则不要引入更多的设计。
跟着书上的货币兑换的例子跑了一遍,原著是用java,我用python,转换有一些问题,最后两章没完成。

接着,跟着pytest文档里的例子跑一遍玩玩。
使用pytest.raises(异常名称)来测试是否发生特定异常。
-q选项代表静默执行。
pytest能发现以test_或_test为前/后缀命名的文件,函数,以及以Test开头的类作为测试对象。
-k 指定执行的测试。
使用tmpdir,pytest会在测试前临时生成一个临时目录。
断言后面可以给出辅助信息。
fixtures用于在测试前设置,使得测试结果可重复。使用@pytest.fixture装饰器。fixtures可以调用其它的fixtures。
参数fixture,pytest有不同的参数化fixture方式:pytest.fixture()允许参数化fixtures函数;@pytest.mark.parametrize允许定义多组变量并在测试函数或类中使用;pytest_generate_tests允许自定义参数化扩展。

最后,找了篇用python实践TDD的文章,照着撸一遍。

我发文章的三个地方,欢迎大家在朋友圈等地方分享,欢迎点“在看”。

我的个人博客地址:https://zwdnet.github.io

我的知乎文章地址: https://www.zhihu.com/people/zhao-you-min/posts

我的微信个人订阅号:赵瑜敏的口腔医学学习园地

欢迎打赏!感谢支持!