Python 三种最流行的 Python 测试框架大 PK

肖哥shelwin · 2019年07月05日 · 最后由 肖哥shelwin 回复于 2019年07月08日 · 2091 次阅读

前言

在进行 Python 程序单元测试时,测试框架的选型是一个首要的问题。面对众多 Python 单元测试框架,我应该选择哪一个?

本文将探讨这个问题。文章的结构如下。首先,介绍单元测试,框架以及测试框架的基本概念;接着,介绍三种最流行的 Python 单元测试框架,分别是unittest, nose 和 pytest;然后,介绍作者关于 Python 单元测试框架选型的思考和心得;最后,总结全文。

基本概念

在介绍具体的 Python 单元测试框架之前,我们先来回顾一些基本概念。

什么是单元测试?单元测试是软件测试的一种类型。顾名思义,单元测试就是测试的对象是程序中的最小单元的测试。程序的最小单元可以是一个函数,一个类,也可以是函数的组合,类的组合。

单元测试是软件测试中最低级别的测试活动,与之相对的更高级别的测试有模块测试,集成系统和系统测试等。单元测试一般由软件开发者而不是独立的测试工程师完成。另外,单元测试有一个隐含的性质,那就是单元测试天然就是自动化的,单元测试属于自动化测试。

什么是框架?首先,框架是一个 “架子”。这个架子能够完成领域内基础的、重要的功能。基于这个已有的架子,我们可以将重心放在面向业务的开发上。

其次,框架也是一个 “框框”。“框框” 为我们设置了有形和无形的约束。所谓有形的约束,就是我们的开发工作需要符合框架的定义、与框架兼容。所谓无形的约束,就是我们的开发工作需要承受框架的缺点和不足 (毕竟,没有十全十美的框架)。

什么是测试框架? 我们知道,软件测试分为手工测试和自动化测试。需要注意的是,一般只有自动化测试才有框架的概念。(自动化) 测试框架,需要提供自动化测试用例编写、自动化测试用例执行、自动化测试报告生成等基础功能

有了测试框架,我们只需要完成和业务高度相关的测试用例设计和实现即可。另外,框架会为我们处理好复杂度与扩展性的问题,我们无需为此操心。

有了这些概念作为支撑,我们就很容易理解什么是 Python 单元测试框架了。所谓 Python 单元测试框架,就是面向 Python 编程语言,服务于 Python 单元测试的自动化测试框架

主流框架

Python 单元测试框架有很多,我们介绍最流行的三种。

unittest

unittest 是 Python 标准库中自带的单元测试框架。unittest 有时候也被称为 PyUnit。就像 JUnit 是 Java 语言的标准单元测试框架一样,unittest(PyUnit) 则是 Python 语言的标准单元测试框架

unittest 支持自动化测试,测试用例的初始化和关闭,测试用例的聚合等功能。unittest 有一个很重要的特性:它通过类 (class) 的方式,将测试用例组织在一起。

一个简单的示例如下:

import unittest

class TestStringMethods(unittest.TestCase):
    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

if__name__=='__main__':
    unittest.main()

执行结果:

...
---------------------
Ran 1 tests in 0.000s
OK

需要注意的是,unittest 有一个关联模块unittest2。但是 unittest2 仅适用于 Python 2.4-2.6。这是因为,从 Python 2.7 开始,unittest 增加一些新的特性。为了在老的版本 Python 2.4-2.6 支持这些特性,提供了 unittest2 这个库。对于 Python 2.7 及之后的版本,unittest 是唯一的。

nose

nose 是 Python 的一个第三方单元测试框架。这意味着,如果要使用 nose,需要先显式安装它:

pip install nose

与 unittest 不同的是,nose 的测试用例并不限制于类。任何函数和类,只要名称匹配一定的条件 (例如,以 test 开头或以 test 结尾等),都会被自动识别为测试用例;并且,为了兼容 unittest, 所有的基于 unitest 编写的测试用例,也会被 nose 自动识别为。

一个简单的 nose 单元测试示例如下:

import nose

def test_example ():
    pass

if __name__ == '__main__':
    nose.runmodule()

执行结果:

...
---------------------
Ran 1 tests in 0.000s
OK

需要注意的是,nose 已经进入维护模式,从github nose上可以看到,nose 最近的一次代码提交还是在2016年5月4日。继承 nose 的是 nose2,但要注意的是,nose2 并不支持 nose 的全部功能,它们的区别可以看这里

nose2 的主要目的是扩展 Python 的标准单元测试库 unittest,因此它的定位是 “带插件的 unittest”。nose2 提供的插件,例如测试用例加载器,覆盖度报告生成器,并行测试等内置插件和第三方插件,让单元测试变得更加完善。

pytest

pytest 是 Python 另一个第三方单元测试库。它的目的是让单元测试变得更容易,并且也能扩展到支持应用层面复杂的功能测试。

pytest 的特性有:

  1. 支持用简单的 assert 语句实现丰富的断言,无需复杂的 self.assert* 函数
  2. 自动识别测试模块和测试函数
  3. 兼容 unittest 和 nose 测试集
  4. 支持 Python3 和 PyPy3
  5. 丰富的插件生态,已有 300 多个各式各样的插件,和活跃的社区

pytest 一个简单的示例如下:

def inc(x):
    return x +1

def test_answer():
    assert inc(3) ==5

执行结果如下:

$ pytest
============================= test session starts=============================
collected 1 items
test_sample.py F
================================== FAILURES===================================
_________________________________ test_answer_________________________________
    def test_answer():
>       assert inc(3)== 5
E       assert 4 == 5
E        +  where 4 = inc(3)

test_sample.py:5: AssertionError
========================== 1 failed in 0.04 seconds===========================

框架选型

(1) 从入门难度看,pytest/nose 优于 unittest

虽然 unittest 是 Python 自带的单元测试库,但是要上手 unittest 是有难度的,既需要了解 testrunner, testsuite, testcase 等基本概念,还需要熟悉面向对象编程。而 pytest/nose 则为我们隐藏了这些细节,因而能够降低入门单元测试的难度。

对于有一定 Python 编程基础的人来说,unittest 是适合的;对于 Python 编程基础较弱的人来说,nose 和 pytest 则比较适合。另外,对比 nose 和 pytest,一般认为 pytest 的入门难度更低

(2) 同为第三方库,pytest 的生态优于 nose/nose2

我们知道,nose 已经进入了维护模式,取代者是 nose2。相比 nose2,pytest 的生态无疑更具优势,社区的活跃度也更高。

例如,在 github 上,截止现在,pytest 的 STAR 数量是 4229,而 nose2 的 STAR 数量是 558;pytest 的提交数量是 10384,而 nose2 的提交数量是 917。最重要的,pytest 的插件数量是 300 多个,远高于 nose2 的 20 多个插件。

如果只需要基本的插件,那么 nose 和 pytest 都是适合的;如果追求单元测试更丰富的插件,那么 pytest 更适合

(3) 从通用性角度看,pytest 优于 unittest 和 nose

与 unittest/nose 不同的是,pytest 不仅能用于单元测试,还能用于更高级别的,面向应用的功能测试。因此,如果需要进行更高级别的测试,则适合采用 Pytest。

总结

在进行 Python 程序测试时,测试框架的选型是一个重要的问题。众多测试框架之间,我到底应该选择哪一个?

本文对比了 unittest,nose 和 pytest 这三种最流行的 Python 单元测试测试,指出了各个框架的特点,指出了在不同场景和不同需求下,哪一种框架更适合。当然,本文的分析还是比较初步的,在实际中,还需要结合具体情况深入分析后再做决定。

我是肖哥 shelwin,一个高质量软件工程实践者和推动者。欢迎扫描下方二维码,添加我的个人公众号测试不将就,获得更多自动化测试, 持续集成, 软件工程实践, Python 编程等领域原创文章。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 1 条回复 时间 点赞

说明下,标题里的框架具体指的是单元测试框架。

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