Python 3 单元测试

一、概念

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

二、doctest

doctest模块提供了一个工具,扫描模块并根据程序中内嵌的文档字符串执行测试。
测试构造就是简单地将他的输出结果剪切并粘贴到文档字符串中。
通过用户提供的例子,强化文档,允许doctest模块确认代码结果与文档是否一致。

嵌入源码

def average(values):
    '''
    >>> print(average([20, 30, 70]))
    40.0
    >>> print(average([10, 15, 20]))
    15.0
    '''
    return sum(values)/len(values)
if __name__ == "__main__":
    import doctest
    doctest.testmod(verbose=True)

测试用例的位置必须放在整个模块文件的开头,或者紧接着对象(模块、函数、类)声明语句的下一行。也就是可以被 doc 这个属性引用到的地方。并非像普通注释一样写在哪里都可以。另:verbose 参数用于控制是否输出详细信息,默认为 False,如果不写,那么运行时不会输出任何东西,除非测试 fail。
输出结果

Trying:
print(average([20, 30, 70]))
Expecting:
40.0
ok
Trying:
print(average([10, 15, 20]))
Expecting:
15.0
ok
1 items had no tests:
main
1 items passed all tests:
2 tests in main.average
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

保存为独立文件

如果不想(或不能)把测试用例写进源代码里,则还可以使用一个独立的文本文件来保存测试用例。

python -m doctest -v example.txt

上述命令中,-m表示引入module,-v表示verbose值为True,输出测试的结果。
测试模块:test.py

def multiply(a, b):
    return a * b

测试用例:example.txt

>>> from py3stdlib import multiply
>>> multiply(3, 4)
12
>>> multiply('a', 3)
'aaa'

在shell中运行

python3 -m doctest -v example.txt

输出结果

Trying:
from py3stdlib import multiply
Expecting nothing
ok
Trying:
multiply(3, 4)
Expecting:
12
ok
Trying:
multiply(‘a’, 3)
Expecting:
‘aaa’
ok
1 items passed all tests:
3 tests in example.txt
3 tests in 1 items.
3 passed and 0 failed.
Test passed.

三、unittest

使用 unittest 的标准流程为:

  1. 从 unittest.TestCase 派生一个子类
  2. 在类中定义各种以 “test_” 打头的方法
  3. 通过 unittest.main() 函数来启动测试

unittest 的一个很有用的特性是 TestCase 的 setUp() 和 tearDown() 方法,它们提供了为测试进行准备和扫尾工作的功能,听起来就像上下文管理器一样。这种功能很适合用在测试对象需要复杂执行环境的情况下。

测试模块:test.py

def multiply(a, b):
    return a * b

测试用例:test.py

#! /usr/bin/python3
# coding=utf-8 
import unittest
from py3stdlib import multiply
class TestM(unittest.TestCase):
    def setUp(self):
        pass
    def test_3_4(self):
        self.assertEqual(multiply(5,6),30)
    def test_str(self):
        self.assertEqual(multiply('a',3),'aaa')
if __name__ == "__main__":
    unittest.main()

直接在shell运行即可

python3 test.py

输出结果
在这里插入图片描述
unittest中有很多方法,本例中用到了assertEqual() 方法。除此之外还有 NotEqual、Is(Not)None、True(False)、Is(Not)Instance 等针对变量值的校验方法;还有一些如 assertRaises()、assertRaisesRegex() 等针对异常、警告和 log 的检查方法;以及如 assertAlmostEqual() 等。

四、nose(推荐使用)

nose不是Python官方发行的标准包,是unittest的扩展。
语法:测试方法必须以test_开头。
测试模块:py3stdlib.py

def multiply(a, b):
    return a * b

测试用例:test.py

#! /usr/bin/python3
# coding=utf-8 
from py3stdlib import multiply
def test_num():
    assert multiply(3,4)==12
def test_str():
    assert multiply('a',3)=='aaa'

安装nosepip3 install nose,执行测试python3 -m nose test.py

5、pytest

参考文档
与nose的区别:

  1. 调用测试的命令不同,pytest 用的是 $ py.test
  2. 创建测试环境(setup/teardown)的 api 不同
    测试文件:test.py
    测试指令:py.test some_test.py -s其中**-s**用于显示print函数
#! /usr/bin/python3
# coding=utf-8 
import pytest 
@pytest.fixture(scope='function')
def setup_function(request):
    def teardown_function():
        print("teardown_function called.")
    request.addfinalizer(teardown_function)
    print('setup_function called.')

@pytest.fixture(scope='module')# 通过显示指定score参数来选择使用的pytest.fixture装饰器
# 有效的 scope 参数限于:'function','module','class','session',默认为 function。
def setup_module(request):
    def teardown_module():
        print("teardown_module called.")
    request.addfinalizer(teardown_module)
    print('setup_module called.')
def test_1(setup_function):
    print('Test_1 called.')
def test_2(setup_module):
    print('Test_2 called.')
def test_3(setup_module):
    print('Test_3 called.')

小结

Part 1单元测试的含义

单元测试可以有效地测试某个程序模块的行为;
测试用例要覆盖常用的输入组合、边界条件和异常;
测试代码要非常简单,如果测试代码太复杂,那么测试代码本身可能就有bug;
测试通过并不意味着无bug,但不通过是肯定有bug.

Part2 四种测试框架的对比

doctest
官方发行。嵌入源码和独立文件。简单,但是无用功太多。
unittest
官方发行。TestCase 的 setUp() 和 tearDown() 方法提供了为测试进行准备和扫尾工作的功能,这种功能很适合用在测试对象需要复杂执行环境的情况下。
nose
不需要使用特定类模板,与unittest兼容性高,实现方式简单,基本隐藏了各种实现细节。nose 不使用特定的格式、不需要一个类容器,不需要额外的API。
pytest
不需要使用特定类模板的角度上,有彩色输出。但它的 setup/teardown 语法与 unittest 的兼容性不如 nose 高,实现方式也不如 nose 直观。
综上所述,比较推荐使用nose。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值