UnitTest 框架 – 快速指南

UnitTest 框架 – 快速指南


UnitTest 框架 – 概述

单元测试是一种软件测试方法,通过它测试源代码的各个单元,例如函数、方法和类,以确定它们是否适合使用。直观地,可以将单元视为应用程序中最小的可测试部分。单元测试是程序员在开发过程中创建的短代码片段。它构成了组件测试的基础。

单元测试可以通过以下两种方式完成 –

Manual Testing 自动化测试

Executing the test cases manually without any tool support is known as manual testing.

  • Since test cases are executed by human resources so it is very time consuming and tedious.

  • As test cases need to be executed manually so more testers are required in manual testing.

  • It is less reliable as tests may not be performed with precision each time because of human errors.

  • No programming can be done to write sophisticated tests which fetch hidden information.

使用自动化工具获取工具支持并执行测试用例称为自动化测试。

  • Fast Automation 运行测试用例的速度明显快于人力资源。

  • 由于使用自动化工具执行测试用例,因此对人力资源投资较少

  • 自动化测试在每次运行时都执行完全相同的操作,并且更加可靠

  • 测试人员可以编写复杂的测试程序以找出隐藏的信息。

JUnit 是 Java 编程语言的单元测试框架。JUnit 在测试驱动开发的发展中一直很重要,并且是源自 JUnit 的统称为 xUnit 的单元测试框架系列之一。您可以在此处找到JUnit 教程

Python 单元测试框架,有时也称为“PyUnit”,是由 Kent Beck 和 Erich Gamma 开发的 JUnit 的 Python 语言版本。自 Python 2.1 版起,PyUnit 构成 Python 标准库的一部分。

Python 单元测试框架支持测试自动化、共享测试的设置和关闭代码、将测试聚合到集合中以及测试独立于报告框架。unittest 模块提供的类可以轻松支持一组测试的这些质量。

本教程是为初学者准备的,帮助他们了解Python测试框架的基本功能。完成本教程后,您会发现自己在使用 Python 测试框架方面处于中等水平的专业知识水平,您可以在此基础上更上一层楼。

您应该具有使用 Python 语言进行软件开发的合理专业知识。我们的Python 教程是开始学习 Python 的好地方。还需要了解软件测试的基础知识。

环境设置

编写测试所需的类可以在“unittest”模块中找到。如果您使用的是旧版本的 Python(Python 2.1 之前的版本),可以从http://pyunit.sourceforge.net/下载该模块但是,unittest 模块现在是标准 Python 发行版的一部分;因此它不需要单独安装。

UnitTest 框架 – 框架

“unittest”支持测试自动化、共享测试的设置和关闭代码、将测试聚合到集合中以及测试独立于报告框架。

unittest 模块提供的类可以轻松支持一组测试的这些质量。

为此,unittest 支持以下重要概念 –

  • 测试夹具– 这表示执行一个或多个测试所需的准备工作,以及任何相关的清理操作。例如,这可能涉及创建临时或代理数据库、目录或启动服务器进程。

  • 测试用例– 这是最小的测试单元。这会检查对特定输入集的特定响应。unittest 提供了一个基类TestCase,可用于创建新的测试用例。

  • 测试套件– 这是测试用例、测试套件或两者的集合。这用于聚合应该一起执行的测试。测试套件由 TestSuite 类实现。

  • 测试运行器– 这是一个组件,用于协调测试的执行并向用户提供结果。运行器可以使用图形界面、文本界面或返回一个特殊值来指示执行测试的结果。

创建单元测试

编写一个简单的单元测试涉及以下步骤 –

步骤 1 – 在您的程序中导入 unittest 模块。

步骤 2 – 定义要测试的函数。在下面的例子中,add() 函数将受到测试。

第 3 步– 通过子类化 unittest.TestCase 创建一个测试用例。

第 4 步– 将测试定义为类内的方法。方法名称必须以“test”开头。

步骤 5 – 每个测试调用 TestCase 类的 assert 函数。有许多类型的断言。以下示例调用 assertEquals() 函数。

第 6 步– assertEquals() 函数将 add() 函数的结果与 arg2 参数进行比较,如果比较失败则抛出 assertionError。

步骤 7 – 最后,从 unittest 模块调用 main() 方法。

import unittest
def add(x,y):
   return x + y
   
class SimpleTest(unittest.TestCase):
   def testadd1(self):
      self.assertEquals(add(4,5),9)
      
if __name__ == '__main__':
   unittest.main()

步骤 8 – 从命令行运行上述脚本。

C:\Python27>python SimpleTest.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

步骤 9 – 以下三个可能是测试的可能结果 –

Sr.No 消息和说明
1

OK

测试通过。‘A’ 显示在控制台上。

2

FAIL

测试未通过,并引发 AssertionError 异常。‘F’ 显示在控制台上。

3

ERROR

该测试引发了 AssertionError 以外的异常。‘E’ 显示在控制台上。

这些结果分别通过“.”、“F”和“E”显示在控制台上。

命令行界面

可以从命令行使用 unittest 模块来运行单个或多个测试。

python -m unittest test1
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method

unittest 支持以下命令行选项。有关所有命令行选项的列表,请使用以下命令 –

Python –m unittest -h

Sr.No 选项和说明
1

-h, –help

显示此消息

2

v, –verbose

详细输出

3

-q, –quiet

最小输出

4

-f, –failfast

第一次失败时停止

5

-c, –catch

捕获 control-C 并显示结果

6

-b, –buffer

在测试运行期间缓冲 stdout 和 stderr

单元测试框架 – API

本章讨论了 unittest 模块中定义的类和方法。本模块有五个主要类。

测试用例类

此类的对象表示最小的可测试单元。它保存测试例程并提供用于准备每个例程和之后清理的钩子。

TestCase 类中定义了以下方法 –

Sr.No 方法和说明
1

setUp()

调用方法来准备测试夹具。这在调用测试方法之前立即调用

2

tearDown()

在调用测试方法并记录结果后立即调用方法。即使测试方法引发异常,也会调用它,

3

setUpClass()

在单个类中运行测试之前调用的类方法。

4

tearDownClass()

在单个类中的测试运行后调用的类方法。

5

run(result = None)

运行测试,将结果收集到作为result传递的测试结果对象中

6

skipTest(reason)

在测试方法或 setUp() 期间调用它会跳过当前测试。

7

debug()

运行测试而不收集结果。

8

shortDescription()

返回测试的单行描述。

灯具

在 TestCase 类中可以编写大量测试。这些测试方法可能需要数据库连接、临时文件或其他资源进行初始化。这些被称为夹具。TestCase 包括一个特殊的钩子来配置和清理测试所需的任何装置。要配置灯具,请覆盖 setUp()。要清理,请覆盖 tearDown()。

在以下示例中,在 TestCase 类中编写了两个测试。他们测试两个值的加减结果。setup() 方法根据每个测试的 shortDescription() 初始化参数。teardown() 方法将在每次测试结束时执行。

import unittest

class simpleTest2(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      if name == "Add":
         self.a = 10
         self.b = 20
         print name, self.a, self.b
      if name == "sub":
         self.a = 50
         self.b = 60
         print name, self.a, self.b
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
if __name__ == '__main__':
   unittest.main()

从命令行运行上面的代码。它提供以下输出 –

C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "test2.py", line 21, in testadd
      self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s

FAILED (failures = 1)

课件

TestCase 类有一个 setUpClass() 方法,该方法可以在 TestCase 类中的单个测试执行之前被覆盖执行。同样,tearDownClass() 方法将在类中的所有测试之后执行。这两种方法都是类方法。因此,它们必须用@classmethod 指令装饰。

以下示例演示了这些类方法的使用 –

import unittest

class TestFixtures(unittest.TestCase):

   @classmethod
   def setUpClass(cls):
      print 'called once before any tests in class'

   @classmethod
   def tearDownClass(cls):
      print '\ncalled once after all tests in class'

   def setUp(self):
      self.a = 10
      self.b = 20
      name = self.shortDescription()
      print '\n',name
   def tearDown(self):
      print '\nend of test',self.shortDescription()

   def test1(self):
      """One"""
      result = self.a+self.b
      self.assertTrue(True)
   def test2(self):
      """Two"""
      result = self.a-self.b
      self.assertTrue(False)
      
if __name__ == '__main__':
unittest.main()

测试套件类

Python 的测试框架提供了一种有用的机制,通过该机制可以根据它们测试的特性将测试用例实例组合在一起。该机制由 unittest 模块中的 TestSuite 类提供。

创建和运行测试套件涉及以下步骤。

步骤 1 – 创建 TestSuite 类的实例。

suite = unittest.TestSuite()

第 2 步– 在套件的 TestCase 类中添加测试。

suite.addTest(testcase class)

第 3 步– 您还可以使用 makeSuite() 方法从类中添加测试

suite = unittest.makeSuite(test case class)

步骤 4 – 也可以在套件中添加单独的测试。

suite.addTest(testcaseclass(""testmethod")

第 5 步– 创建 TestTestRunner 类的对象。

runner = unittest.TextTestRunner()

第 6 步– 调用 run() 方法来运行套件中的所有测试

runner.run (suite)

TestSuite 类中定义了以下方法 –

Sr.No 方法和说明
1

addTest()

在测试套件中添加测试方法。

2

addTests()

添加来自多个 TestCase 类的测试。

3

run()

运行与此套件关联的测试,将结果收集到测试结果对象中

4

debug()

运行与此套件关联的测试而不收集结果。

5

countTestCases()

返回此测试对象表示的测试数量

以下示例显示了如何使用 TestSuite 类 –

import unittest
class suiteTest(unittest.TestCase):
   def setUp(self):
      self.a = 10
      self.b = 20
      
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertTrue(result == 100)
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
      
def suite():
   suite = unittest.TestSuite()
##   suite.addTest (simpleTest3("testadd"))
##   suite.addTest (simpleTest3("testsub"))
   suite.addTest(unittest.makeSuite(simpleTest3))
   return suite
   
if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   runner.run (test_suite)

您可以通过取消注释行和具有 makeSuite() 方法的注释语句来试验 addTest() 方法。

测试加载器类

unittest 包具有 TestLoader 类,用于从类和模块创建测试套件。默认情况下,当调用 unittest.main(0 方法时会自动创建 unittest.defaultTestLoader 实例。显式实例,但是可以自定义某些属性。

在以下代码中,使用 TestLoader 对象将来自两个类的测试收集到一个列表中。

import unittest
testList = [Test1, Test2]
testLoad = unittest.TestLoader()

TestList = []
for testCase in testList:
   testSuite = testLoad.loadTestsFromTestCase(testCase)
   TestList.append(testSuite)
   
newSuite = unittest.TestSuite(TestList)
runner = unittest.TextTestRunner()
runner.run(newSuite)

下表显示了 TestLoader 类中的方法列表 –

S.No 方法和说明
1

loadTestsFromTestCase()

返回包含在 TestCase 类中的所有测试用例的套件

2

loadTestsFromModule()

返回给定模块中包含的所有测试用例的套件。

3

loadTestsFromName()

返回一组给定字符串说明符的所有测试用例。

4

discover()

通过从指定的起始目录递归到子目录中找到所有测试模块,并返回一个 TestSuite 对象

测试结果类

此类用于编译有关已成功测试和已失败测试的信息。TestResult 对象存储一组测试的结果。TestRunner.run() 方法返回一个 TestResult 实例。

TestResult 实例具有以下属性 –

Sr.No 属性和描述
1

Errors

一个包含两元组 TestCase 实例和保存格式化回溯的字符串的列表。每个元组代表一个引发意外异常的测试。

2

Failures

一个包含两元组 TestCase 实例和保存格式化回溯的字符串的列表。每个元组代表一个测试,其中使用 TestCase.assert*() 方法显式发出失败信号。

3

Skipped

一个包含两元组 TestCase 实例和包含跳过测试原因的字符串的列表。

4

wasSuccessful()

如果到目前为止运行的所有测试都已通过,则返回 True,否则返回 False。

5

stop()

可以调用此方法来表示应中止正在运行的测试集。

6

startTestRun()

在执行任何测试之前调用一次。

7

stopTestRun()

在所有测试执行后调用一次。

8

testsRun

到目前为止运行的测试总数。

9

Buffer

如果设置为 true,sys.stdoutsys.stderr将在 startTest() 和 stopTest() 被调用之间缓冲。

以下代码执行测试套件 –

if __name__ == '__main__':
   runner = unittest.TextTestRunner()
   test_suite = suite()
   result = runner.run (test_suite)
   
   print "---- START OF TEST RESULTS"
   print result

   print "result::errors"
   print result.errors

   print "result::failures"
   print result.failures

   print "result::skipped"
   print result.skipped

   print "result::successful"
   print result.wasSuccessful()
   
   print "result::test-run"
   print result.testsRun
   print "---- END OF TEST RESULTS"

执行时的代码显示以下输出 –

---- START OF TEST RESULTS
<unittest.runner.TextTestResult run = 2 errors = 0 failures = 1>
result::errors
[]
result::failures
[(<__main__.suiteTest testMethod = testadd>, 'Traceback (most recent call last):\n
   File "test3.py", line 10, in testadd\n 
   self.assertTrue(result == 100)\nAssert
   ionError: False is not true\n')]
result::skipped
[]
result::successful
False
result::test-run
2
---- END OF TEST RESULTS

UnitTest 框架 – 断言

Python 测试框架使用 Python 的内置 assert() 函数来测试特定条件。如果断言失败,将引发 AssertionError。然后测试框架会将测试标识为失败。其他异常被视为错误。

unittest 模块中定义了以下三组断言函数 –

  • 基本布尔断言
  • 比较断言
  • 集合的断言

基本断言函数评估操作的结果是 True 还是 False。所有断言方法都接受一个msg参数,如果指定,则用作失败时的错误消息。

Sr.No 方法和说明
1

assertEqual(arg1, arg2, msg = None)

测试arg1arg2是否相等。如果比较的值不相等,则测试将失败。

2

assertNotEqual(arg1, arg2, msg = None)

测试arg1arg2不相等。如果值比较相等,则测试将失败。

3

assertTrue(expr, msg = None)

测试expr是否为真。如果为 false,则测试失败

4

assertFalse(expr, msg = None)

测试expr是否为假。如果为真,则测试失败

5

assertIs(arg1, arg2, msg = None)

测试arg1arg2评估为同一个对象。

6

assertIsNot(arg1, arg2, msg = None)

测试arg1arg2不计算为同一个对象。

7

assertIsNone(expr, msg = None)

测试expr是否为 None。如果不是 None,则测试失败

8

assertIsNotNone(expr, msg = None)

测试expr不是 None。如果没有,测试失败

9

assertIn(arg1, arg2, msg = None)

测试arg1是否在arg2 中

10

assertNotIn(arg1, arg2, msg = None)

测试arg1不在arg2 中

11

assertIsInstance(obj, cls, msg = None)

测试objcls 的一个实例

12

assertNotIsInstance(obj, cls, msg = None)

测试obj不是cls的实例

上面的一些断言函数是在以下代码中实现的 –

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertEqual(4 + 5,9)
   def test2(self):
      self.assertNotEqual(5 * 2,10)
   def test3(self):
      self.assertTrue(4 + 5 == 9,"The result is False")
   def test4(self):
      self.assertTrue(4 + 5 == 10,"assertion fails")
   def test5(self):
      self.assertIn(3,[1,2,3])
   def test6(self):
      self.assertNotIn(3, range(5))

if __name__ == '__main__':
   unittest.main()

当上面的脚本运行时,test2、test4和test6会显示失败,其他运行成功。

FAIL: test2 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 9, in test2
      self.assertNotEqual(5*2,10)
AssertionError: 10 == 10

FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 13, in test4
      self.assertTrue(4+5==10,"assertion fails")
AssertionError: assertion fails

FAIL: test6 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python27\SimpleTest.py", line 17, in test6
      self.assertNotIn(3, range(5))
AssertionError: 3 unexpectedly found in [0, 1, 2, 3, 4]

----------------------------------------------------------------------            
Ran 6 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 3)

第二组断言函数是比较断言 –

  • assertAlmostEqual(第一,第二,位置 = 7,味精 = 无,增量 = 无)

    测试第一第二近似(或不近似)通过计算差,四舍五入到小数点的给定数目等于地方(默认7),

  • assertNotAlmostEqual (first, second, places, msg, delta)

    通过计算差值、四舍五入到给定的小数位数(默认为 7)并与零进行比较来测试第一个和第二个是否近似相等。

    在上述两个函数中,如果提供了 delta 而不是地方,那么第一个和第二个之间的差异必须小于或等于(或大于)delta。

    提供 delta 和 place 会引发 TypeError。

  • assertGreater(第一,第二,味精=无)

    根据方法名称测试first是否大于second否则,测试将失败。

  • assertGreaterEqual(第一,第二,味精=无)

    根据方法名称测试first是否大于或等于second如果没有,测试将失败

  • assertLess(第一,第二,味精=无)

    根据方法名称测试first小于second如果没有,测试将失败

  • assertLessEqual(第一,第二,味精=无)

    根据方法名称测试first是否小于或等于second否则,测试将失败。

  • assertRegexpMatches (text, regexp, msg = None)

    测试正则表达式搜索是否与文本匹配。如果失败,错误消息将包括模式和文本。regexp 可以是一个正则表达式对象,也可以是一个包含适合re.search()使用的正则表达式的字符串

  • assertNotRegexpMatches (text, regexp, msg = None)

    验证正则表达式搜索与text不匹配失败并显示错误消息,包括模式和匹配文本部分regexp可以是一个正则表达式对象,也可以是一个包含适合re.search()使用的正则表达式的字符串

断言函数在以下示例中实现 –

import unittest
import math
import re

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertAlmostEqual(22.0/7,3.14)
   def test2(self):
      self.assertNotAlmostEqual(10.0/3,3)
   def test3(self):
      self.assertGreater(math.pi,3)
   def test4(self):
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")

if __name__ == '__main__':
   unittest.main()

上面的脚本将 test1 和 test4 报告为失败。在 test1 中,22/7 的除法不在 3.14 的小数点后 7 位以内。类似地,由于第二个参数与第一个参数中的文本匹配,因此 test4 会导致 AssertionError。

=====================================================FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 7, in test1
      self.assertAlmostEqual(22.0/7,3.14)
AssertionError: 3.142857142857143 != 3.14 within 7 places
================================================================
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 13, in test4
      self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
AssertionError: Regexp matched: 'Point' matches 'Point' in 'Tutorials Point (I)
Private Limited'
----------------------------------------------------------------------

Ran 4 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

集合断言

这组断言函数旨在与 Python 中的集合数据类型一起使用,例如 List、Tuple、Dictionary 和 Set。

Sr.No 方法和说明
1

assertListEqual (list1, list2, msg = None)

测试两个列表是否相等。如果不是,则会构建一条错误消息,仅显示两者之间的差异。

2

assertTupleEqual (tuple1, tuple2, msg = None)

测试两个元组是否相等。如果不是,则会构建一条错误消息,仅显示两者之间的差异。

3

assertSetEqual (set1, set2, msg = None)

测试两组是否相等。如果不是,则构建一个错误消息,列出集合之间的差异。

4

assertDictEqual (expected, actual, msg = None)

测试两个字典是否相等。如果不是,则会构造一条错误消息,显示字典中的差异。

以下示例实现了上述方法 –

import unittest

class SimpleTest(unittest.TestCase):
   def test1(self):
      self.assertListEqual([2,3,4], [1,2,3,4,5])
   def test2(self):
      self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
   def test3(self):
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})

if __name__ == '__main__':
   unittest.main()

在上面的示例中,test1 和 test3 显示 AssertionError。错误消息显示 List 和 Dictionary 对象的差异。

FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 5, in test1
      self.assertListEqual([2,3,4], [1,2,3,4,5])
AssertionError: Lists differ: [2, 3, 4] != [1, 2, 3, 4, 5]

First differing element 0:
2
1

Second list contains 2 additional elements.
First extra element 3:
4

- [2, 3, 4]
+ [1, 2, 3, 4, 5]
? +++       +++

FAIL: test3 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "asserttest.py", line 9, in test3
      self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
AssertionError: {1: 11, 2: 22} != {1: 11, 2: 22, 3: 33}
- {1: 11, 2: 22}
+ {1: 11, 2: 22, 3: 33}
?              +++++++
                                                                                  
----------------------------------------------------------------------            
Ran 3 tests in 0.001s                                                             
                                                                                  
FAILED (failures = 2)

UnitTest 框架 – 测试发现

TestLoader 类有一个discover() 函数。Python 测试框架使用它来进行简单的测试发现。为了兼容,包含测试的模块和包必须可以从顶级目录导入。

以下是测试发现的基本命令行用法 –

Python –m unittest discover

解释器尝试从当前目录和内部目录递归加载包含测试的所有模块。其他命令行选项是 –

Sr.No 选项和说明
1

-v, –verbose

详细输出

2

-s, –start-directory

目录 开始发现的目录(默认)

3

-p, –pattern

模式 匹配测试文件的模式(默认为 test*.py)

4

-t, –top-level-directory

directory 项目的顶级目录(默认为启动目录)

例如,为了在“tests”目录中发现名称以“assert”开头的模块中的测试,使用以下命令行 –

C:\python27>python –m unittest –v –s "c:\test" –p "assert*.py"

测试发现通过导入来加载测试。一旦测试发现从您指定的开始目录中找到所有测试文件,它就会将路径转换为要导入的包名称。

如果您将起始目录作为包名而不是目录路径提供,那么discover 假定它从哪个位置导入就是您想要的位置,因此您不会收到警告。

UnitTest 框架 – 跳过测试

自 Python 2.7 起添加了对跳过测试的支持。可以有条件地和无条件地跳过单个测试方法或 TestCase 类。该框架允许将某个测试标记为“预期失败”。此测试将“失败”,但不会在 TestResult 中计为失败。

要无条件跳过方法,可以使用以下 unittest.skip() 类方法 –

import unittest

   def add(x,y):
      return x+y

class SimpleTest(unittest.TestCase):
   @unittest.skip("demonstrating skipping")
   def testadd1(self):
      self.assertEquals(add(4,5),9)

if __name__ == '__main__':
   unittest.main()

由于skip() 是一个类方法,所以它以@ 标记为前缀。该方法采用一个参数:描述跳过原因的日志消息。

执行上述脚本时,控制台上会显示以下结果 –

C:\Python27>python skiptest.py
s
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK (skipped = 1)

字符“s”表示已跳过测试。

跳过测试的另一种语法是在测试函数中使用实例方法 skipTest()。

def testadd2(self):
   self.skipTest("another method for skipping")
   self.assertTrue(add(4 + 5) == 10)

以下装饰器实现测试跳过和预期失败 –

Sr.No 方法和说明
1

unittest.skip(reason)

无条件跳过装饰测试。原因应该描述为什么要跳过测试。

2

unittest.skipIf(condition, reason)

如果条件为真,则跳过装饰测试。

3

unittest.skipUnless(condition, reason)

除非条件为真,否则跳过装饰测试。

4

unittest.expectedFailure()

将测试标记为预期失败。如果运行时测试失败,则该测试不计为失败。

以下示例演示了条件跳过和预期失败的使用。

import unittest

class suiteTest(unittest.TestCase):
   a = 50
   b = 40
   
   def testadd(self):
      """Add"""
      result = self.a+self.b
      self.assertEqual(result,100)

   @unittest.skipIf(a>b, "Skip over this routine")
   def testsub(self):
      """sub"""
      result = self.a-self.b
      self.assertTrue(result == -10)
   
   @unittest.skipUnless(b == 0, "Skip over this routine")
   def testdiv(self):
      """div"""
      result = self.a/self.b
      self.assertTrue(result == 1)

   @unittest.expectedFailure
   def testmul(self):
      """mul"""
      result = self.a*self.b
      self.assertEqual(result == 0)

if __name__ == '__main__':
   unittest.main()

在上面的例子中, testsub() 和 testdiv() 将被跳过。在第一种情况下 a>b 为真,而在第二种情况下 b == 0 不为真。另一方面, testmul() 已被标记为预期失败。

运行上述脚本时,两个跳过的测试显示“s”,预期失败显示为“x”。

C:\Python27>python skiptest.py
Fsxs
================================================================
FAIL: testadd (__main__.suiteTest)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
   File "skiptest.py", line 9, in testadd
      self.assertEqual(result,100)
AssertionError: 90 != 100

----------------------------------------------------------------------
Ran 4 tests in 0.000s

FAILED (failures = 1, skipped = 2, expected failures = 1)

UnitTest 框架 – 异常测试

Python 测试框架提供以下断言方法来检查是否引发异常。

assertRaises(异常,可调用,*args,**kwds)

测试在使用任何位置或关键字参数调用函数时是否引发异常(第一个参数)。如果引发预期的异常,则测试通过,如果引发另一个异常,则测试为错误,如果未引发异常,则测试失败。要捕获一组异常中的任何一个,可以将包含异常类的元组作为异常传递。

在下面的示例中,定义了一个测试函数来检查是否引发 ZeroDivisionError。

import unittest

def div(a,b):
   return a/b
class raiseTest(unittest.TestCase):
   def testraise(self):
      self.assertRaises(ZeroDivisionError, div, 1,0)

if __name__ == '__main__':
   unittest.main()

testraise() 函数使用 assertRaises() 函数来查看调用 div() 函数时是否发生被零除。上面的代码将引发异常。但是将参数更改为 div() 函数如下 –

self.assertRaises(ZeroDivisionError, div, 1,1)

当使用这些更改运行代码时,测试失败,因为 ZeroDivisionError 不会发生。

F
================================================================
FAIL: testraise (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 7, in testraise
      self.assertRaises(ZeroDivisionError, div, 1,1)
AssertionError: ZeroDivisionError not raised

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures = 1)

assertRaisesRegexp(异常,正则表达式,可调用,*args,**kwds)

测试正则表达式匹配引发异常的字符串表示。regexp 可以是一个正则表达式对象,也可以是一个包含适合 re.search() 使用的正则表达式的字符串。

以下示例显示了如何使用 assertRaisesRegexp() –

import unittest
import re

class raiseTest(unittest.TestCase):
   def testraiseRegex(self):
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
      
if __name__ == '__main__':
   unittest.main()

在这里, testraseRegex() 测试不会作为第一个参数失败。“Point”位于第二个参数字符串中。

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:/Python27/raiseTest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
AssertionError: TypeError not raised
----------------------------------------------------------------------

但是,更改如下所示 –

self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")

将抛出 TypeError 异常。因此,将显示以下结果 –

================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
   File "raisetest.py", line 11, in testraiseRegex
      self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")
AssertionError: "invalid" does not match 
   "first argument must be string or compiled pattern"
----------------------------------------------------------------------

UnitTest 框架 – 时间测试

Junit,Java 单元测试框架(Pyunit 是 JUnit 的实现)有一个方便的超时选项。如果测试花费的时间超过指定的时间,它将被标记为失败。

Python 的测试框架不包含任何对超时的支持。但是,名为 timeout-decorator 的第三方模块可以完成这项工作。

从以下位置下载并安装模块 –

https://pypi.python.org/packages/source/t/timeout-decorator/timeout-decorator-0.3.2.tar.gz

  • 在代码中导入 timeout_decorator
  • 在测试之前放置超时装饰器
  • @timeout_decorator.timeout(10)

如果此行下方的测试方法花费的时间超过此处提到的超时(10 分钟),则会引发 TimeOutError。例如 –

import time
import timeout_decorator

class timeoutTest(unittest.TestCase):

   @timeout_decorator.timeout(5)
   def testtimeout(self):
      print "Start"
   for i in range(1,10):
      time.sleep(1)
      print "%d seconds have passed" % i
      
if __name__ == '__main__':
   unittest.main()

单元测试框架 – Unittest2

unittest2 是在 Python 2.7 及更高版本中添加到 Python 测试框架的附加功能的反向移植。它经过测试可以在 Python 2.6、2.7 和 3.* 上运行。最新版本可以从https://pypi.python.org/pypi/unittest2下载

要使用 unittest2 而不是 unittest,只需将 import unittest 替换为 import unittest2。

unittest2 中的类派生自 unittest 中的相应类,因此应该可以使用 unittest2 测试运行基础结构,而无需立即将所有测试切换为使用 unittest2。如果您打算实现新功能,请从unittest2.TestCase而不是 unittest.TestCase子类化您的测试用例

以下是 unittest2 的新功能 –

  • addCleanups以更好地管理资源

  • 包含许多新的断言方法

  • assertRaises作为上下文管理器,之后可以访问异常

  • 具有模块级别的装置,例如setUpModuletearDownModule

  • 包括用于从模块或包加载测试的load_tests协议

  • TestResult 上的startTestRunstopTestRun方法

在 Python 2.7 中,您可以使用python -m unittest <args>调用 unittest 命令行功能(包括测试发现)

相反,unittest2 带有一个脚本 unit2。

unit2 discover
unit2 -v test_module

UnitTest 框架 – 信号处理

unittest 的 -c/–catch 命令行选项以及catchbreak参数提供了在测试运行期间更有效地处理 control-C 启用 catch break 行为后,control-C 将允许当前运行的测试完成,然后测试运行将结束并报告到目前为止的所有结果。第二个 control-c 将以通常的方式引发 KeyboardInterrupt 。

如果调用了 unittest 处理程序但未安装 signal.SIGINT 处理程序,则它会调用默认处理程序。这通常是替换已安装处理程序并将其委托给它的代码的预期行为。对于需要禁用 unittest control-c 处理的单个测试,可以使用 removeHandler() 装饰器。

以下实用程序功能在测试框架中启用 control-c 处理功能 –

unittest.installHandler()

安装 control-c 处理程序。收到一个signal.SIGINT 时,所有注册的结果都会调用 TestResult.stop() 。

unittest.registerResult(result)

注册一个TestResult对象以进行 control-c 处理。注册结果会存储对它的弱引用,因此它不会阻止结果被垃圾收集。

unittest.removeResult(result)

删除已注册的结果。一旦结果被删除,那么 TestResult.stop() 将不再在该结果对象上调用以响应 control-c。

unittest.removeHandler(function = None)

当不带参数调用时,此函数将删除已安装的 control-c 处理程序。此函数还可用作测试装饰器,以在执行测试时临时删除处理程序。

GUI 测试运行程序

安装 unittest 模块以交互地发现和运行测试。这个实用程序,一个 Python 脚本 ‘inittestgui.py’ 使用 Tkinter 模块,它是 TK 图形工具包的 Python 端口。它为发现和运行测试提供了一个易于使用的 GUI。

Python unittestgui.py

运行测试

单击“发现测试”按钮。出现一个小对话框,您可以在其中选择要运行测试的目录和模块。

发现测试

最后,点击开始按钮。将从选定的路径和模块名称中发现测试,结果窗格将显示结果。

结果窗格

要查看单个测试的详细信息,请在结果框中选择并单击测试 –

个人测试详情

如果在 Python 安装中没有找到此实用程序,可以从项目页面http://pyunit.sourceforge.net/获取它

类似的,基于 wxpython 工具包的实用程序也可用。

UnitTest 框架 – Doctest

Python’标准发行版包含’Doctest’模块。该模块的功能使搜索看起来像交互式 Python 会话的文本片段成为可能,并执行这些会话以查看它们是否完全按照所示工作。

Doctest 在以下场景中非常有用 –

  • 通过验证所有交互式示例仍然按文档工作来检查模块的文档字符串是否是最新的。

  • 通过验证来自测试文件或测试对象的交互式示例是否按预期工作来执行回归测试。

  • 为一个包编写教程文档,用输入输出示例进行大量说明

在 Python 中,“docstring”是一个字符串文字,它作为类、函数或模块中的第一个表达式出现。执行套件时会忽略它,但会被编译器识别并放入封闭类、函数或模块__doc__属性中。由于它可以通过自省获得,因此它是对象文档的规范场所。

通常的做法是将 Python 代码不同部分的示例用法放在 docstring 中。doctest 模块允许验证这些文档字符串是否与代码中的间歇性修订保持同步。

在以下代码中,定义了一个穿插示例用法的阶乘函数。为了验证示例用法是否正确,请调用 doctest 模块中的 testmod() 函数。

"""
This is the "example" module.

The example module supplies one function, factorial(). For example,

>>> factorial(5)
120
"""

def factorial(x):
   """Return the factorial of n, an exact integer >= 0.
   >>> factorial(-1)
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
   """
   
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testmod()

输入上述脚本并将其保存为 FactDocTest.py 并尝试从命令行执行此脚本。

Python FactDocTest.py

除非示例失败,否则不会显示任何输出。现在,将命令行更改为以下内容 –

Python FactDocTest.py –v

控制台现在将显示以下输出 –

C:\Python27>python FactDocTest.py -v
Trying:
   factorial(5)
Expecting:
   120
ok
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
2 items passed all tests:
   1 tests in __main__
   1 tests in __main__.factorial
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

另一方面,如果 factorial() 函数的代码没有在文档字符串中给出预期的结果,则会显示失败结果。例如,将上述脚本中的 f = 2 更改为 f = 1 并再次运行 doctest。结果如下 –

Trying:
   factorial(5)
Expecting:
   120
**********************************************************************
File "docfacttest.py", line 6, in __main__
Failed example:
factorial(5)
Expected:
   120
Got:
   240
Trying:
   factorial(-1)
Expecting:
   Traceback (most recent call last):
      ...
   ValueError: x must be >= 0
ok
1 items passed all tests:
   1 tests in __main__.factorial
**********************************************************************
1 items had failures:
   1 of 1 in __main__
2 tests in 2 items.
1 passed and 1 failed.
***Test Failed*** 1 failures.

Doctest:检查文本文件中的示例

doctest 的另一个简单应用是测试文本文件中的交互式示例。这可以通过 testfile() 函数来完成。

以下文本存储在名为“example.txt”的文本文件中。

Using ''factorial''
-------------------
This is an example text file in reStructuredText format. First import
''factorial'' from the ''example'' module:
   >>> from example import factorial
Now use it:
   >>> factorial(5)
   120

文件内容被视为文档字符串。为了验证文本文件中的示例,请使用 doctest 模块的 testfile() 函数。

def factorial(x):
   if not x >= 0:
      raise ValueError("x must be >= 0")
   f = 1
   for i in range(1,x+1):
      f = f*i
   return f
   
if __name__ == "__main__":
   import doctest
   doctest.testfile("example.txt")
  • 与 testmod() 一样,除非示例失败,否则 testfile() 不会显示任何内容。如果一个例子失败了,那么失败的例子和失败的原因被打印到控制台,使用与 testmod() 相同的格式。

  • 在大多数情况下,交互式控制台会话的复制和粘贴工作正常,但 doctest 并未尝试对任何特定 Python shell 进行精确模拟。

  • 任何预期的输出都必须紧跟在包含代码的最终 ‘>>> ‘ 或 ‘… ‘ 行之后,并且预期的输出(如果有)延伸到下一个 ‘>>> ‘ 或全空白行。

  • 预期输出不能包含全空白行,因为这样的行被用来表示预期输出的结束。如果预期的输出确实包含一个空行,请将 <BLANKLINE> 放在您的 doctest 示例中,每个地方都需要一个空行。

UnitTest 框架 – Doctest API

doctest API 围绕以下两个容器类,用于存储来自 docstrings 的交互式示例 –

  • 示例– 单个 Python 语句,与其预期输出配对。

  • DocTest – 示例集合,通常从单个文档字符串或文本文件中提取。

定义了以下附加处理类以查找、解析和运行以及检查 doctest 示例 –

  • DocTestFinder – 查找给定模块中的所有文档字符串,并使用 DocTestParser 从包含交互式示例的每个文档字符串创建 DocTest。

  • DocTestParser – 从字符串(例如对象的文档字符串)创建一个 doctest 对象。

  • DocTestRunner – 在 doctest 中执行示例,并使用 OutputChecker 来验证它们的输出。

  • OutputChecker – 将 doctest 示例的实际输出与预期输出进行比较,并确定它们是否匹配。

DocTestFinder 类

它是一个处理类,用于从给定对象的文档字符串及其包含对象的文档字符串中提取与给定对象相关的文档测试。目前可以从以下对象类型中提取 Doctests——模块、函数、类、方法、静态方法、类方法和属性。

这个类定义了 find() 方法。它返回由对象的文档字符串或其包含的任何对象的文档字符串定义的 DocTest 列表

DocTestParser 类

它是一个处理类,用于从字符串中提取交互式示例,并使用它们来创建 DocTest 对象。这个类定义了以下方法 –

  • get_doctest() – 从给定的字符串中提取所有 doctest 示例,并将它们收集到DocTest对象中。

  • get_examples(string[, name]) – 从给定的字符串中提取所有 doctest 示例,并将它们作为Example对象的列表返回行号从 0 开始。可选参数 name 是标识此字符串的名称,仅用于错误消息。

  • parse(string[, name]) – 将给定的字符串分成示例和中间文本,并将它们作为交替示例和字符串的列表返回示例的行号从0 开始。可选参数 name 是标识此字符串的名称,仅用于错误消息。

DocTestRunner 类

这是一个处理类,用于执行和验证 DocTest 中的交互式示例。其中定义了以下方法 –

报告开始()

报告测试运行器即将处理给定的示例。提供此方法是为了允许DocTestRunner 的子类自定义它们的输出;不应该直接调用

报告_成功()

报告给定的示例运行成功。提供此方法是为了允许 DocTestRunner 的子类自定义它们的输出;不应直接调用它。

报告失败()

报告给定的示例失败。提供此方法是为了允许DocTestRunner 的子类自定义它们的输出;不应直接调用它。

report_unexpected_exception()

报告给定的示例引发了意外异常。提供此方法是为了允许 DocTestRunner 的子类自定义它们的输出;不应直接调用它。

运行(测试)

运行test 中的示例(一个 DocTest 对象),并使用 writer 函数out显示结果

总结([详细])

打印此 DocTestRunner 已运行的所有测试用例的摘要,并返回一个命名元组TestResults(failed,试图)。可选的详细参数控制摘要的详细程度。如果未指定详细程度,则使用 DocTestRunner 的详细程度。

输出检查器类

此类用于检查 doctest 示例的实际输出是否与预期输出匹配。

此类中定义了以下方法 –

检查输出()

如果示例的实际输出 ( got ) 与预期输出 ( want )匹配,则返回True如果这些字符串相同,则始终认为它们匹配;但是根据测试运行程序使用的选项标志,几种非完全匹配类型也是可能的。有关选项标志的更多信息,请参阅选项标志指令部分

output_difference()

返回一个字符串,描述给定示例的预期输出(example)和实际输出(got之间的差异

DocTest 与 Unittest 的集成

doctest 模块提供了两个函数,可用于从包含 doctest 的模块和文本文件创建单元测试测试套件。要与 unittest 测试发现集成,请在您的测试模块中包含一个 load_tests() 函数 –

import unittest
import doctest
import doctestexample

def load_tests(loader, tests, ignore):
   tests.addTests(doctest.DocTestSuite(doctestexample))
   return tests

将形成来自 unittest 和 doctest 的测试的组合 TestSuite,它现在可以由 unittest 模块的 main() 方法或 run() 方法执行。

以下是使用 doctest 从文本文件和模块创建unittest.TestSuite实例的两个主要功能

doctest.DocFileSuite()

它用于将 doctest 测试从一个或多个文本文件转换为unittest.TestSuite返回的 unittest.TestSuite 将由 unittest 框架运行,并运行每个文件中的交互式示例。如果文件中的任何示例失败,则合成单元测试失败,并引发failureException异常,显示包含测试的文件的名称和(有时是近似的)行号。

doctest.DocTestSuite()

它用于将模块的 doctest 测试转换为unittest.TestSuite

返回的 unittest.TestSuite 将由 unittest 框架运行,并运行模块中的每个 doctest。如果任何 doctests 失败,则合成单元测试失败,并引发failureException异常,显示包含测试的文件的名称和(有时是近似的)行号

在幕后,DocTestSuite()从 doctest.DocTestCase 实例中创建了一个unittest.TestSuite,DocTestCase 是 unittest.TestCase 的子类。

类似地,DocFileSuite() 从 doctest.DocFileCase 实例中创建一个 unittest.TestSuite,DocFileCase 是 DocTestCase 的子类。

因此,创建 unittest.TestSuite 的两种方法都会运行 DocTestCase 的实例。当您自己运行 doctest 函数时,您可以通过将选项标志传递给 doctest 函数来直接控制正在使用的 doctest 选项。

但是,如果您正在编写单元测试框架,则单元测试最终会控制测试运行的时间和方式。框架作者通常希望控制 doctest 报告选项(也许,例如,由命令行选项指定),但没有办法通过 unittest 将选项传递给 doctest 测试运行程序。

UnitTest 框架 – Py.test 模块

2004 年,Holger Krekel 将他的std重命名为(只是稍微不那么容易混淆)名称“py”,该包的名称经常与 Python 附带的标准库的名称混淆。虽然该包包含几个子包,但现在几乎完全以其 py.test 框架而闻名。

py.test 框架为 Python 测试设立了一个新的标准,并且在今天非常受许多开发人员的欢迎。它为测试编写引入的优雅和 Pythonic 习语使以更紧凑的风格编写测试套件成为可能。

py.test 是 Python 标准 unittest 模块的无样板替代品。尽管它是一个功能齐全且可扩展的测试工具,但它拥有简单的语法。创建测试套件就像编写具有几个功能的模块一样简单。

py.test 在所有 POSIX 操作系统和 WINDOWS (XP/7/8) 上运行,Python 版本为 2.6 及更高版本。

安装

使用以下代码加载当前 Python 发行版中的 pytest 模块以及 py.test.exe 实用程序。可以使用两者运行测试。

pip install pytest

用法

您可以简单地使用 assert 语句来断言测试期望。pytest 的断言自省将智能地报告断言表达式的中间值,使您无需了解JUnit 遗留方法的许多名称

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

使用以下命令行运行上述测试。运行测试后,控制台上会显示以下结果 –

C:\Python27>scripts\py.test -v test_sample.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyth
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 1 items
test_sample.py::test_answer FAILED
================================== FAILURES =====================
_________________________________ test_answer _________________________________
   def test_answer():
>  assert func(3) == 5
E     assert 4 == 5
E     + where 4 = func(3)
test_sample.py:7: AssertionError
========================== 1 failed in 0.05 seconds ====================

通过使用 –m 开关包含 pytest 模块,也可以从命令行运行测试。

python -m pytest test_sample.py

将多个测试分组在一个类中

一旦您开始进行多个测试,通常将测试按逻辑分组到类和模块中是有意义的。让我们编写一个包含两个测试的类 –

class TestClass:
   def test_one(self):
      x = "this"
      assert 'h' in x
   def test_two(self):
      x = "hello"
      assert hasattr(x, 'check')

将显示以下测试结果 –

C:\Python27>scripts\py.test -v test_class.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyt
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 2 items
test_class.py::TestClass::test_one PASSED
test_class.py::TestClass::test_two FAILED
================================== FAILURES =====================
_____________________________ TestClass.test_two ______________________________
self = <test_class.TestClass instance at 0x01309DA0>

   def test_two(self):
      x = "hello"
>  assert hasattr(x, 'check')
E     assert hasattr('hello', 'check')

test_class.py:7: AssertionError
===================== 1 failed, 1 passed in 0.06 seconds ======================

鼻子测试 – 框架

鼻子项目于 2005 年发布,也就是py.test获得现代外观的第二年它由 Jason Pellerin 编写,用于支持 py.test 开创的相同测试习语,但在一个更易于安装和维护的包中。

模块可与PIP工具的帮助下安装

pip install nose

这将在当前 Python 发行版中安装nose 模块以及一个nosetest.exe,这意味着可以使用此实用程序以及使用-m 开关运行测试。

C:\python>nosetests –v test_sample.py
Or
C:\python>python –m nose test_sample.py

鼻子当然unittest.TestCase子类收集测试我们还可以编写简单的测试函数,以及不是 unittest.TestCase 子类的测试类。鼻子还提供了许多有用的功能,用于编写定时测试、异常测试和其他常见用例。

鼻子自动收集测试。无需手动将测试用例收集到测试套件中。运行测试是响应式的,因为一旦加载了第一个测试模块鼻子就会开始运行测试。

与 unittest 模块一样,nose支持包、模块、类和测试用例级别的夹具,因此可以尽可能少地进行昂贵的初始化。

基本用法

让我们考虑与之前使用的脚本类似的 nosetest.py –

# content of nosetest.py
def func(x):
   return x + 1
   
def test_answer():
   assert func(3) == 5

为了运行上述测试,请使用以下命令行语法 –

C:\python>nosetests –v nosetest.py

控制台上显示的输出如下 –

nosetest.test_answer ... FAIL
================================================================
FAIL: nosetest.test_answer
----------------------------------------------------------------------
Traceback (most recent call last):
   File "C:\Python34\lib\site-packages\nose\case.py", line 198, in runTest
      self.test(*self.arg)
   File "C:\Python34\nosetest.py", line 6, in test_answer
      assert func(3) == 5
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures = 1)

通过在上面的命令行中使用with-doctest选项,可以将鼻子与 DocTest 集成

\nosetests --with-doctest -v nosetest.py

您可以在测试脚本中使用鼻子

import nose
nose.main()

如果您不希望测试脚本在成功时以 0 和失败时以 1 退出(如 unittest.main),请改用nose.run() –

import nose
result = nose.run()

如果测试运行成功,则结果为 true,如果失败或引发未捕获的异常,则结果为 false。

鼻子支持包、模块、类和测试级别的夹具(设置和拆卸方法)。与 py.test 或 unittest 固定装置一样,setup 总是在任何测试(或测试包和模块的测试集合)之前运行;如果安装成功完成,则拆卸运行,无论测试运行的状态如何。

鼻子测试 – 工具

鼻子.tools 模块提供了许多您可能会发现有用的测试辅助工具,包括用于限制测试执行时间和测试异常的装饰器,以及在 unittest.TestCase 中找到的所有相同的 assertX 方法。

  • 鼻子.tools.ok_(expr, msg = None) – 断言的简写。

  • 鼻子.tools.eq_(a, b, msg = None) – ‘assert a == b, “%r != %r” % (a, b) 的简写

  • none.tools.make_decorator(func) – 包装一个测试装饰器以正确复制装饰函数的元数据,包括鼻子的附加内容(即设置和拆卸)。

  • 鼻子.tools.raises(*exceptions) – 测试必须引发预期的异常之一才能通过。

  • 鼻子.tools.timed(limit) – 测试必须在指定的时间内完成才能通过

  • nose.tools.istest(func) – 将函数或方法标记为测试的装饰器

  • nose.tools.nottest(func) – 将函数或方法标记为非测试的装饰器

参数化测试

Python 的测试框架 unittest 没有运行参数化测试用例的简单方法。换句话说,您不能轻松地从外部将参数传递到unittest.TestCase 中

但是,pytest 模块端口以几种集成良好的方式测试参数化 –

  • pytest.fixture()允许您在夹具函数级别定义参数化。

  • @pytest.mark.parametrize允许在函数或类级别定义参数化。它为特定的测试函数或类提供多个参数/夹具集。

  • pytest_generate_tests可以实现您自己的自定义动态参数化方案或扩展。

第三方模块“nose-parameterized”允许使​​用任何 Python 测试框架进行参数化测试。它可以从这个链接下载 – https://github.com/wolever/nose-parameterized

觉得文章有用?

点个广告表达一下你的爱意吧 !😁