通用技术 python unittest 入门

codeskyblue · 2017年07月17日 · 最后由 皮一下很开心 回复于 2018年03月06日 · 1609 次阅读

简介

虽然本人对 python 的 unittest 不熟悉,但还是硬着头皮把这篇文章写了,希望写完之后,自己能对这个单测框架了解的多一些。

2018 5.1 假期来临,突然想到还有一篇没有写完的文章,接杯热水继续写起来。

基本概念

python unittest 实际上是参考 jUnit 实现的,甚至连命名都跟 java 一样都是驼峰命名(这个有点让有强迫症的人看了隐隐的不爽)

unittest 包含 4 个基本概念

  • test fixture

    代表准备和清理的操作。像setUp testDown 都属于 test fixture

  • test case

    代表最基本的测试单元,检查在特定输入的情况下是否有一个特定的输出。通过集成 unitest 中的TestCase类,可以快速的写出一个 test case

  • test suite

    test suite 由一组 test case 组成,不过其中也可以包含 test suite。代表所有的 case 合集

  • test runner

    test runner 运行所有的 case,并将结果展现给用户。展现的方式可以是图形或文本,等等。

要测试的内容

测试的对象是一个简单的 Player 类 (代码保存为 player.py),通过 move 方法,可以改变 player 的 x, y 坐标

# coding: utf-8

class Player(object):
    """ Player with position and can move in 2D world """

    def __init__(self):
        self.x = 0
        self.y = 0

    def move(self, xoff, yoff):
        self.x += xoff
        self.y += yoff

if __name__ == '__main__':
    p = Player()
    p.move(1, 2)
    print("Player position: ({}, {})".format(p.x, p.y))

简单的使用例子

继续我们刚才写的代码,我们再写一些测试代码。

# coding: utf-8
# @Filename: simple_player_test.py
#
import unittest
from player import Player

class SimplePlayerTest(unittest.TestCase):
    def setUp(self):
        self.p = Player()

    def runTest(self):
        self.p.move(1, 2)
        assert self.p.x == 1
        assert self.p.y == 2

    def tearDown(self):
        print("tearDown calling")

上面的代码中,我们继承了 TestCase 类,重写了其中的setUp, runTesttearDown方法。setUp通常用来准备测试环境。之后的runTest会包含一些测试的操作。之后的tearDown做一些环境的清理操作。
如果setUp运行过程中跑出了异常,runTest不会被运行,tearDown方法也不会运行。
如果setUp执行成功, 那么无论runTest是否成功,tearDown方法都将被执行。

如果测试用例中有AssertionError异常抛出,测试框架会任务用例失败(Failure)。其他非 “assert"检查抛出的异常会被测试框架任务错误(Error)

具体的用例之后,我们后面再说。先保持一点耐心。
使用上面的刚写好的SimplePlayerTest先创建一个实例。

testCase = SimplePlayerTest()

包含多个测试方法的测试用例类

有时候可能我们很好多东西要测试,然后共用setUp函数。将原来的测试类代码稍微修改下为

class SimplePlayerTest(unittest.TestCase):
    def setUp(self):
        self.p = Player()

    def tearDown(self):
        self.p.x = 0
        self.p.y = 0

    def testMoveUp(self):
        self.p.move(0, 1)
        assert self.p.x == 0 and self.p.y == 1

    def testMoveLeft(self);
        self.p.move(-1, 0)
        assert self.p.x == -1 and self.p.y == 0

这个测试用例中我们没有提供 runTest 方法,而是用了两个不同的测试方法。创建类实例时需要想构造器传递方法名称,指明哪个测试方法将要被运行。

moveUpCase = SimplePlayerTest("testMoveUp")
moveLeftCase = SimplePlayerTest("testMoveLeft")

将测试用例聚合成测试套件

测试用例实例可以根据它们所测试的特性组合到一起。PyUnit 为此提供了一个机制叫做” 测试套件 “(test suite)。它由 unittest 模块中的 TestSuite 类表示:

suite = unittest.TestSuite()
suite.addTest(moveUpCase)
suite.addTest(moveLeftCase)

因为创建一个包含很多相似名称的测试方法的 TestCase 子类是一种很常见的模式,所以 unittest 模块提供一个便捷方法,makeSuite,来 创建一个由测试用例类内所有测试用例组成的测试套件:

suite = unittest.makeSuite(SimplePlayerTest, 'test')

需要注意的是,当使用 makeSuite 方法时,测试套件运行每个测试用例的顺序是由测试方法名根据 Python 内建函数 cmp 所排序的顺序而决定的

所以如果有两个函数testA(), testB() 无论testA定义在后面还是前面,testA都是先与testB执行。

未完待续

参考资料

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 4 条回复 时间 点赞
  • 补充补充:这个图帮助理解基本概念挺有用的

赞,希望还能有继续更深入的讲解

Jay_ 回复

最近比较忙,之后会补全的

期待更新 ing................

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册