单元测试 - 交互式学Python | 莫烦Python

单元测试

作者: 莫烦 编辑: 莫烦 2021-05-14

Test! Test! Test! 重要的事说三遍。 不管是你自用的代码还是写给别人用的代码都需要测试。 尤其是你要写一些功能服务给别人用的时候,免不了要先自测有没有问题。 如果上一节内容我们学习的是怎样处理错误, 那这一节内容我们就是学习怎么样避免错误。

对于我来说,我通常处理的代码量比较大,牵扯到的资源相对多,所以我很多时候并不知道哪里会不会有错误。 所以我非常依赖与测试。让自动化测试帮我处理任何改动可能带来的问题。

什么是 Unittest

在很多语言中都有 Unittest,他是一种语言比较通用的测试功能。越流行,越好用的库,比如机器学习中的 Tensorflow, 它的 unittest 也就越多。原因也很简单,为了保证我写的,真的是我想要的这件事。

unittest

每一种语言的 Unittest 方法并不都一样。在 Python 中,我们常用一个原生的 unittest单元测试

什么是单元测试呢?其实就是不直接测你的全套程序逻辑,而是将你的小功能模块拆开了一个个测。 这样做的目的非常明确,只有你能每一小步都做好,你的整体才不容易出错。 在 Python 中,如果你还没有接触过 unittest,你的测试流程很可能是运行整套逻辑,看看它会不会报错。

然后发现报错之后,在来看看是哪里报错了,接着就是修改报错的代码。这种方式比较适合

  1. 小型项目,
  2. 没有多少个功能的项目,
  3. 而且项目功能之间并不会有任何联系。

如果你不满足上面这几点,那要不试试 unittest? 在 Python 中,一个简单的 unittest 是下面这样。下面我们继承了 unittest.TestCase, 还不明白继承是啥意思的同学,请看到这里

上面两个都没什么问题。但是当我们再测试另一个除以零的 case 的时候,它就会帮我报出问题啦。

unittest 规范

前面我们已经展示了一个特别小的案例。现在我们来说说写 unittest 的思路和规范吧。 首先 unittext 不会被其他人使用到,纯粹是你自己为了验证自己写的代码有没有问题的方式。 另外,你可以按照 unittest 当中的 case 为蓝本,去完善你原函数的功能。 就好像有了一个目标,你要为了这个目标去开发功能一样。

我举一个例子,我想要开发一个:

  1. 输入 1 返回 2
  2. 输入 -1 返回 3 3。输入其他任何数,返回 1

这样的一个功能,那我就可以先写 unittest 当中的 case,比如下面,我不会先写 my_func 里面的内容,而是先把我的规划写好, 要验收的指标写好。然后后面我在开发功能。

另外还有一个不成文的规范,我的这个 my_func() 通常是写在另一个 Python 文件中的,比如 all_my_func.py, 我在测试文件中,比如 test.py 是会将 all_my_func.pymy_func() 引入进来做测试的。 这样测试就不会和我原本的功能文件混杂在一起了。有点类似于下图的分工。

unittest

而且很多时候,你并不只有一个功能要测试,你还会有很多其他的,想一起测试。这也很好办。 而且如果你其中某一个有问题,他也会单独指出到底是哪一个有问题,问题在哪。 你多把玩一下,看看它的特性。

用 Python 命令执行测试

注意,有些人可能会比较喜欢通过 Python 的指令来运行测试,比如下面这样。test.py 就是我们写 test 的文件啦,如上面的测试都可以写在 test.py 中。

python -m unittest tests.py

能测哪些 assert

在 unittest 的模块中,我们还有特别丰富的测试方式,比如上面你看到的 self.assertTrue()self.assertEqual()。我在下面再列一些比较常用的。

assert 含义
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertTrue(condition) condition 是不是 True
assertFalse(condition) condition 是不是 False
assertGreater(a, b) a > b
assertGreaterThan(a, b) a >= b
assertLess(a, b) a < b
assertLessEqual(a, b) a <= b
assertIs(a, b) a is b,a 和 b 是不是同一对象
assertIsNot(a, b) a is not b,a 和 b 是不是不同对象
assertIsNone(a) a is None,a 是不是 None
assertIsNotNone(a) a is not None,a 不是 None?
assertIn(a, b) a in b, a 在 b 里面?
assertNotIn(a, b) a not in b,a 不在 b 里?
assertRaises(err) 通常和 with 一起用,判断 with 里的功能是否会报错(上面练习有用到过)

测单独的功能

如果你写了很多 test,但是只想 test 某些功能,咋整?有复杂的办法,也有简单的。先说复杂的,你在你的 test.py 中,将代码最下边的 unittest.main() 替换成下面这段代码中那些 TestSuite()TextTestRunner() 部分。但是这样写不太友善,因为你测试的变动挺多的, 一会儿想测这些,一会儿想测些别的,这样写非常不灵活。

我们还可以不用上面 unittest.TestSuite() 的写法,直接用 Python 的命令来执行不同的 test。 下面这种写法灵活性更强,我们也能实现上面的那些 suite 方法。

python -m unittest tests.TestFunc.test_func2

总结

测试!测试!测试!别忘了测试。测试真的很重要,很多时候还节约了你 debug 的时间,赋能你的大项目。


降低知识传递的门槛

莫烦很常从互联网上学习知识,开源分享的人是我学习的榜样。 他们的行为也改变了我对教育的态度: 降低知识传递的门槛免费 奉献我的所学正是受这种态度的影响。 通过 【赞助莫烦】 能让我感到认同,我也更有理由坚持下去。