Python nose测试大法

[注明:本文最初发布于简书,然而。。。]

Python作为一门简单易学的编程语言,现在长期位于编程语言榜的前三。在人工智能的第二次浪潮涌起之前,因为简单快速容易维护,Python在很多系统中是作为“胶水语言”存在的。而现今时代因为出现大量数据处理的需求,以及在大数据集上的分析和推演的需求,包括人工智能的广泛运用,使得Python语言换发了第二春,众多的机器学习框架和库都是用Python例如pytorch和tensorflow等等。另外,很多数据分析师或工程师都选择了Python作为主要开发语言。

大量软件系统被开发出来,为了保证系统的质量,测试是不可或缺的。这里全栈哥布鲁斯给大家介绍一下常见的Python测试框架。包括nose, pytest和locust。同学们跟着全栈哥布鲁斯的节奏,开始精进吧。这一篇我们先从Python nose测试框架开始。

一、nose是什么?

nose是一个单元测试的框架,它扩展了Python的标准库unittest,让用户更方便地编写单元测试。Python标准库中提供了单元测试的框架unittest,读者可以自行访问unittest — Unit testing framework — Python 3.8.13 documentation了解更多细节。那么标准库中的unittests包有什么问题呢,主要是比较繁琐,例如每个测试用例必须是unittests.TestCase的子类,而且测试用例的组织也不灵活,unittests中提供了unittest.TestSuite来将一个个test case组织起来形成更大的suite。后边会有文章专门介绍unittests这个标准库的用法和实践。

nose库的官方文档(英文)在这里,Note to Users — nose 1.3.7 documentation

二、nose怎么使用?

首先我们需要安装nose。跟其他现代的Python库一样,推荐使用`pip`来安装nose。 在PyPI网站上,搜索nose可以看到最新的版本是1.3.7。地址在nose · PyPI

$ pip install nose

安装好了之后,可以运行nosetests -h来检验一下。

$ nosetests -h

三、nose有什么特性?

nosetests提供了很丰富的功能,例如支持使用正则表达式发现测试用例,支持第三方插件扩充功能,支持测试用例的超时,兼容xUnit样式的报告生成,能够生成代码覆盖率的报告等等。很多工程师选择使用nose,因为它具有简单、灵活、可扩展的特点。

我们从下面的示例代码开始,看看这些特点。

# file: src/calculator.py

# 实现一个简单的计算器,因为是demo的用途,仅仅支持两个数的加法和乘法。

class SimpleCalculator:

    def __init__(self):

        print("initialize a calculator")

    def add(self, x, y):

        return x + y

    def multiply(self, x, y):

        return x * y

下面是对应的测试代码。

# tests/test_calculator.py

from calculator import SimpleCalculator

def test_add():

    calc = SimpleCalculator()

    assert 2022 == calc.add(2000, 22)

def test_multiply():

    calc = SimpleCalculator()

    assert 15 == calc.multiply(3, 5)

接下来用nosetests命令行撸一把。

$ nosetests -v

test_calculator.test_add ... ok

test_calculator.test_multiply ... ok

----------------------------------------------------------------------

Ran 2 tests in 0.008s

OK

是不是很简单?

Python语言是一门动态语言,跟其他的像C++,JAVA等高级语言相比它的一个特点和优势就是灵活。例如Python语言中的duck typing,就不用像C++,JAVA等等一定需要用继承的方式来构建严格的类型系统。这个动态性的优势,也使得Python的测试框架可以做得很人性化。例如nose中的测试用例,并不要求必须派生于某个基类(如unittests.TestCase),而是只需要符合testMatch的模式就可以了。这里的testMatch在nose官方文档中有着详细的解释,它指的是nose收集和识别测试用例的规则,一般使用正则表达式来定义。缺省情况下所有的模块只要是文件名以“test”(或"Test")开头就会被nose收集,模块中的函数或者类,如果是"test"(或"Test")开头的会被认定为测试用例。上面测试代码中的"test_add"和“test_multiply”除了名字以test开头,它们是普通的函数。这个比unittests中规定的繁文缛节,要清爽多了。

除了这个,nose还支持使用配置文件(config files)来定义参数。这个特性在实际开发中有很多用途,例如我们可以为UT和IT创建不同的配置文件,也可以将(大型)项目中的功能通过配置文件分配到不同的测试子集中。对于config的用法,这里不做展开细讲了。

四、最佳实践介绍

1. 测试用例的收集

虽然说nose通过testMatch可以支持各种定制化的测试组织和命名方式,但是为了提供项目的工程化水平,让项目代码更容易维护,实践中还是以简单清晰的结构为上策。

例如

- package名字一般为test_xxx_yyy或xxx_yyy_test;

- module名字一般为test_aaa或aaa_test;

- case名字一般为test_my_func或class TestMyModule之类的。

对于测试用例的组织来说,一致的清晰的方式容易理解容易维护。nose缺省的testMatch就能够搞定,而且对于新加入项目的同事来说也非常友好。

2. 测试用例的运行

nose运行测试用例的方式比较灵活。例如

下面例子中运行了两个包中的测试。

通常情况下使用

$ nosetests -v

运行所有的测试用例。

另外一个常常用到的办法是使用tags。nose内建的插件“attribute selector”可以根据用户指定的attribute来筛选特定的测试用例。例如

from nose.plugins.attrib import attr

@attr('smoke')

def test_an_important_case():

    #implementation goes here

    pass

结果示例如下

$ nosetests -a "smoke" -v

test_hello.test_an_important_case ... ok

----------------------------------------------------------------------

Ran 1 test in 0.009s

OK

关于这个插件,更详细的用法可以参考

https://nose.readthedocs.io/en/latest/plugins/attrib.html

3. 测试报告的生成

nose自身的测试报告是简约风格,但是项目可能需要更详细的报告或者需要在Jenkins等CI工具中进行集成。这一点可以通过nosetests的选项--with-xunit完美解决。

$ nosetests --with-xunit

它会生成一个JUnit兼容的报告文件叫做nosetests.xml。当然你可以通过选项--xunit-file指定这个文件的生成位置和文件名。

4. 内建的插件

nose还有一些其他的插件,勤奋又聪明的读者可以自己动手学习和实践。文档地址是 https://nose.readthedocs.io/en/latest/plugins/builtin.html

五、那么问题呢?

nose也有自身的缺点。一个最大的问题是,这个库以及很久没有更新了。似乎原作者不再想维护了,有些可惜。作者推荐用户迁移到py.test或者nose2,或者干脆直接使用Python标准库中的unittests。因为py.test现在的人气很旺,所以全栈哥布鲁斯也推荐读者去使用py.test。本人在新的项目中也使用了py.test,感兴趣的读者可以跟我多多交流互相学习。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bruce Jia(上海)

熬夜码字换酒钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值