python 五种常见的测试框架

猿友 2021-01-12 11:34:24 浏览数 (8227)
反馈

一. unittest

unittest 和 JUnit类似,可以说是python的标准单元测试框架,所以有时也被人称为 PyUnit。它使用起来和xUnit 家族其他成员类似。 用的人也比较多。兼容 python2 以及python3 。

个人比较喜欢用这个,主要之前用过JUnit,用这个上手就很快。而且属于python自动集成,不用额外的安装包,感觉是该有的都有了,用着方便。

官网示例:

按 Ctrl+C 复制代码

import unittest

class TestStringMethods(unittest.TestCase):

def test_upper(self): self.assertEqual('foo'.upper(), 'FOO')

def test_isupper(self): self.assertTrue('FOO'.isupper()) self.assertFalse('Foo'.isupper())

def test_split(self): s = 'hello world' self.assertEqual(s.split(), ['hello', 'world']) # check that s.split fails when the separator is not a string with self.assertRaises(TypeError): s.split(2)

if name == 'main': unittest.main()

二. unittest2

unittest2 可以说是一个针对 unittest 测试框架新特性的补丁。它很大程度上和 unittest 都类似。然后还添加了一些 unittest 没有的方法。

三. pytest

看了一下,pytest 文档还是蛮详细的。比较关注的一点是,pytest 直接可以通过 @pytest.mark.parametrize 进行参数化,而 unittest 则需要借助 DDT。

官网示例:

# content of test_sample.py
def inc(x):
  return x + 1
​
def test_answer():
  assert inc(3) == 5

执行如下:

$ pytest
======= test session starts ========
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
​
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.12 seconds ========

四. nose

nose 扩展了 unittest,从而使得测试更容易。

一般可以用 unittest 方式写用例,写完之后用 nose 来执行。nose 的测试收集方式还是很方便的。

还有一个特定就是,nose 可以采用 @with_setup() 来定义方法的 setup 和 teardown。

官方示例:

def setup_func():
  "set up test fixtures"
​
def teardown_func():
  "tear down test fixtures"
​
@with_setup(setup_func, teardown_func)
def test():
  "test ..."

五. doctest

doctest 模块会搜索那些看起来像交互式会话的 Python 代码片段,然后尝试执行并验证结果。

doctest 中,如果要写测试用例,只需要在写在以 ''' '''包围的文档注释即可,也就是可以被 doc 这个属性引用到的地方。这点比较特别,跟其他单元测试框架都不一样。但是我觉得这样的话就注定了 doctest 不适合大型测试,因为做不到代码和测试的分离。

import doctest
​
"""
This is the "example" module.
​
The example module supplies one function, factorial(). For example,
​
>>> factorial(5)
120
"""
​
def factorial(n):
  """Return the factorial of n, an exact integer >= 0.
​
  >>> [factorial(n) for n in range(6)]
  [1, 1, 2, 6, 24, 120]
  >>> factorial(30)
  265252859812191058636308480000000
  >>> factorial(-1)
  Traceback (most recent call last):
      ...
  ValueError: n must be >= 0
​
  Factorials of floats are OK, but the float must be an exact integer:
  >>> factorial(30.1)
  Traceback (most recent call last):
      ...
  ValueError: n must be exact integer
  >>> factorial(30.0)
  265252859812191058636308480000000
​
  It must also not be ridiculously large:
  >>> factorial(1e100)
  Traceback (most recent call last):
      ...
  OverflowError: n too large
  """
​
  import math
  if not n >= 0:
      raise ValueError("n must be >= 0")
  if math.floor(n) != n:
      raise ValueError("n must be exact integer")
  if n+1 == n: # catch a value like 1e300
      raise OverflowError("n too large")
  result = 1
  factor = 2
  while factor <= n:
      result *= factor
      factor += 1
  return result
​
​
if __name__ == "__main__":
  doctest.testmod(verbose=True)

verbose 参数用于控制是否输出详细信息,默认为 False ,如果不写,那么运行时不会输出任何东西,除非测试 fail。

输出如下:

Trying:
  [factorial(n) for n in range(6)]
Expecting:
  [1, 1, 2, 6, 24, 120]
ok
Trying:
  factorial(30)
Expecting:
  265252859812191058636308480000000
ok
Trying:
  factorial(-1)
Expecting:
  Traceback (most recent call last):
      ...
  ValueError: n must be >= 0
ok
Trying:
  factorial(30.1)
Expecting:
  Traceback (most recent call last):
      ...
  ValueError: n must be exact integer
ok
Trying:
  factorial(30.0)
Expecting:
  265252859812191058636308480000000
ok
Trying:
  factorial(1e100)
Expecting:
  Traceback (most recent call last):
      ...
  OverflowError: n too large
ok
1 items had no tests:
  __main__
1 items passed all tests:
  6 tests in __main__.factorial
6 tests in 2 items.
6 passed and 0 failed.
Test passed.

推荐好课:python3入门、python3进阶


0 人点赞