Python unittest单元测试框架及断言方法

1. Python unittest单元测试框架介绍

Python unittest框架是Python自带的一个单元测试框架,可以用来对Python代码的质量进行测试。它可以让开发者在编写代码时写下一些测试用例,来检查代码的正确性和完整性。通过测试用例的实施与测试结果的反馈,程序员可以调试程序并确保程序的正确性。

unittest框架提供了一个TestRunner类,他可以自动执行测试用例,并输出测试结果,包括用例的成功数、失败数、错误数、耗时等信息。此外,unittest还提供了丰富的测试用例管理器,使得我们可以灵活地组织测试用例并指定执行顺序。

2. 基本用法

2.1 编写测试用例

在unittest框架中,测试用例需要继承unittest.TestCase类,并且需要在测试方法名前使用“test”前缀。例如下面的示例定义了一个简单的加法测试用例add_test():

import unittest

class TestMath(unittest.TestCase):

def test_add(self):

self.assertEqual(1+1,2)

if __name__ == '__main__':

unittest.main()

在这个例子中,我们定义了TestMath类,继承自unittest.TestCase类,其方法test_add()用于测试加法运算的正确性。在这个测试用例中,我们使用了断言方法self.assertEqual()来检查实际结果是否等于期望结果。如果断言失败,则说明测试用例执行失败。运行这个测试用例,我们得到如下的输出:

.

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

Ran 1 test in 0.000s

OK

这个输出信息告诉我们,本次测试执行了一个测试用例(“.”前缀表示测试通过),耗时0秒,所有测试用例通过(“OK”表示所有测试用例均通过)。

2.2 执行测试用例

executing tests in bulk(批量执行测试)是unittest的特点之一。可以通过多种方式运行测试用例,例如:

unittest.main()

可通过在命令行中运行测试程序来运行测试用例

python test_math.py

此外,unittest还提供了一些其他的方式来运行测试用例,例如在PyCharm中通过运行test_math.py脚本来执行测试用例。

2.3 断言方法

在unittest框架中,断言是验证测试用例的正确性的主要方式。unittest框架提供了各种各样的断言方法,包括:

assertEqual(a, b):验证a == b

assertNotEqual(a, b):验证a != b

assertTrue(x):验证bool(x) is True

assertFalse(x):验证bool(x) is False

assertIs(a, b):验证a is b

assertIsNot(a, b):验证a is not b

assertIsNone(x):验证x is None

assertIsNotNone(x):验证x is not None

assertIn(a, b):验证a in b

assertNotIn(a, b):验证a not in b

assertIsInstance(a, b):验证isinstance(a, b)

assertNotIsInstance(a, b):验证not isinstance(a, b)

例如,在我们上面的例子中,我们使用了assertEqual()方法验证了1+1的结果是否等于2。除了这个方法以外,在我们的每个测试用例中,都可以使用其他的断言方法来验证我们的测试结果的正确性。

2.4 使用装饰器

unittest框架还提供了一些装饰器,可以让我们更加方便地管理测试用例。例如,如果我们有一个需要测试的函数,在测试用例中调用这个函数可能会比较繁琐。我们可以使用@unittest.expectedFailure装饰器将这个测试用例标记为预期失败的测试用例,这样即使测试结果失败也不会影响程序运行。

class TestMath(unittest.TestCase):

@unittest.expectedFailure

def test_subtract(self):

self.assertEqual(1-1,0)

在这个例子中,我们将方法test_subtract()使用@unittest.expectedFailure修饰为预期失败的测试用例,即如果测试失败,程序也不会终止。运行这个测试用例,我们得到如下输出:

F

======================================================================

FAIL: test_subtract (__main__.TestMath)

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

Traceback (most recent call last):

File "unittest_math.py", line 7, in test_subtract

self.assertEqual(1-1,0)

AssertionError: -1 != 0

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

Ran 1 test in 0.000s

FAILED (failures=1, expected failures=1)

这个输出信息告诉我们,这次测试执行了一个测试用例(“F”前缀表示测试失败),耗时0秒,其中有一个测试用例失败(后面的详细信息给出了失败的原因和失败的测试用例名称),并且有一个预期失败的测试用例(“expected failures=1”表示这个测试用例是预期失败的)。

3.高级用法

3.1 跳过测试用例

在开发中,我们有时候会遇到无法或者不需要编写测试用例的情况。针对这种情况,unittest还提供了一个@unittest.skip装饰器,可以让我们跳过某些测试用例执行,例如下面的示例使用@unittest.skip装饰器跳过了一个简单的除法测试用例:

class TestMath(unittest.TestCase):

@unittest.skip("skip this test")

def test_divide(self):

self.assertEqual(1/0,1)

def test_multiply(self):

self.assertEqual(1*2,2)

这个测试用例定义了一个除法测试,我们可以使用skip()方法跳过这个测试用例的执行。结果是,测试用例中的其他测试不受影响,只有这个测试用例被跳过了。测试结果如下:

.

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

Ran 2 tests in 0.000s

OK (skipped=1)

这个输出信息告诉我们,本次测试执行了两个测试用例(“.”前缀表示测试通过),耗时0秒,其中一个测试用例被跳过了(“skipped=1”表示一个测试用例被跳过了)。

3.2 测试套件

测试套件是unittest框架中的一个重要概念,可以用来将多个测试用例组织在一起,共同执行。unittest中的测试套件有以下几种:

TestCase

TestSuite

TestLoader

其中,TestCase表示一个测试用例,TestSuite表示一个测试套件,TestLoader表示一个测试用例加载器。

在unittest中,TestSuite是所有测试用例的容器。我们可以用TestSuite将多个测试用例汇集在一起,形成一个完整的测试套件。在这个套件中,所有的测试用例都将被依次执行,直到所有的测试用例都执行完成。例如下面的示例中,我们定义了两个测试用例add_test()和subtract_test(),然后我们将这两个测试用例组合成一个测试套件:

def suite():

suite = unittest.TestSuite()

suite.addTest(TestMath('test_add'))

suite.addTest(TestMath('test_subtract'))

return suite

if __name__ == '__main__':

runner = unittest.TextTestRunner()

test_suite = suite()

runner.run(test_suite)

在这个示例中,我们定义了一个函数suite(),用于组合测试用例。suite()负责将两个测试用例add_test()和subtract_test()组合成一个测试套件,并返回这个测试套件。在主程序中,我们使用unittest.TextTestRunner()类来执行测试用例,然后通过执行suite()函数来实现组合测试用例的功能。运行这个脚本,我们得到如下的输出:

..

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

Ran 2 tests in 0.000s

OK

这个输出信息告诉我们,本次测试执行了两个测试用例(“.”前缀表示测试通过),耗时0秒,所有的测试用例都通过了(“OK”表示所有测试用例均通过)。

3.3 测试用例加载器

在unittest框架中,TestLoader用于自动搜索和加载测试用例。TestLoader可以搜索指定目录下的所有测试脚本,并将其中的所有测试用例都加载进来。我们可以使用TestLoader的discover()方法实现测试用例的加载,例如下面的示例使用discover()方法查找当前目录下的所有测试文件并运行测试用例:

if __name__ == '__main__':

loader = unittest.TestLoader()

start_dir = '.'

suite = loader.discover(start_dir)

runner = unittest.TextTestRunner()

runner.run(suite)

在这个示例中,我们先使用TestLoader类的discover()方法查找当前目录下的所有测试脚本,然后将所有找到的测试用例加入到测试套件中,最后使用unittest.TextTestRunner()类执行测试套件。

3.4 设置setUp()和tearDown()方法

在实际的测试中,我们往往需要在执行测试用例前进行一些初始化工作(setUp())、在执行测试用例后进行一些清理工作(tearDown())。unittest框架提供了setUp()和tearDown()方法,可以用于在测试用例执行前后执行一些额外的操作。例如下面的示例中,我们定义了一个setUp()方法,用于进行测试套件的初始化,然后定义了一个tearDown()方法,用于关闭测试套件:

class TestMath(unittest.TestCase):

def setUp(self):

self.test_file = open('test.dat','w')

def tearDown(self):

self.test_file.close()

def test_add(self):

self.assertEqual(1+1,2)

def test_subtract(self):

self.assertEqual(1-1,0)

在这个示例中,我们定义了setUp()方法,在测试用例执行前打开一个test.dat文件,并且定义了tearDown()方法,在测试用例执行后关闭这个文件。这样,在每次测试用例执行前,test.dat文件将被打开,在测试用例执行后,test.dat文件将被关闭。

总结

Python unittest框架提供了一个方便的测试框架,能够进行Python代码的自动化测试。它提供了丰富的断言方法、测试用例管理器、测试套件、测试用例加载器以及setUp()和tearDown()方法等工具,可以让程序员更加轻松地编写高质量的测试代码。随着Python在软件开发中的广泛应用,unittest框架的重要性也日益凸显。

后端开发标签