背景

1. 学习资料:

官网: https://docs.python.org/2.7/library/unittest.html

https://docs.python.org/3/library/unittest.html

IBM Python自动单元测试框架: http://www.ibm.com/developerworks/cn/linux/l-pyunit/

2. python其他类似的工具

doctest: https://docs.python.org/2.7/library/doctest.html#module-doctest

unittest2: https://pypi.python.org/pypi/unittest2

nose: https://nose.readthedocs.org/en/latest/

3. 定义

unittest,有时也叫"PyUnit",是Python语言版本的单元测试框架。和JAVA语言的JUnit类似。

unittest 主要分为以下几个模块:

test fixture:

指的是测试之前需要做的准备工作以及相关的清理工作。比如,新建暂时数据库或代理数据库,目录,或者启动服务器进程。这里主要就是指 setup 以及teardown 函数。

test case(TestCase):
test case是测试的最小单元。它检查一组特定输入的结果。unittest提供一个基类,TestCase,我们可以使用TestCase来新建新的测试用例。

test suite(TestSuite):
test suite是test case的集合,也可以是test suite的集合。它用来将所有一起执行的测试集成在一起。

test runner(TestRunner):
test runner负责执行测试并且提供测试结果。runner可能使用图形接口、文字接口、或者返回一个特殊值来指定测试结果。

示例

1. 测试用例组成(TestCase)

所有的测试用例必须继承自类 unittest.TestCase ,一般测试用例方法名以 test开头。一个测试用例类内部可以定义一个或多个测试用例方法,比如下面就定义了3个方法。

import unittest

class TestStringMethods(unittest.TestCase):

    def setUp(self):
print("This is setup") def test_upper(self):
print("This is test_upper")
self.assertEqual('foo'.upper(), 'FOO') def test_isupper(self):
print("This is test_isupper")
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper()) def test_split(self):
print("This is test_split")
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) def tearDown(self):
print("This is tearDown") if __name__ == '__main__':
unittest.main()

脚本上右键,选择 Run -> Run as Python unit-test ,就可以看到控制台输出如下:

Finding files... done.
Importing test modules ... done. This is setup
This is test_isupper
This is tearDown
This is setup
This is test_split
This is tearDown
This is setup
This is test_upper
This is tearDown
----------------------------------------------------------------------
Ran 3 tests in 0.004s OK

可以看到,每个测试用例方法执行之前都会调用 setUp方法,每个测试用例方法执行结束都会调用 tearDown方法。

一般会把测试用例执行前的准备工作放到setUp方法里面,比如WEB测试的登录操作。setUp执行时如果抛出异常,后边的test都不会被执行,该用例会被标记为error。

一般会把测试用例执行后的清理工作放到tearDown方法里面,比如WEB测试的关闭浏览器操作。只要setUp执行成功,tearDown就会被执行。tearDown抛出异常的话,测试结果会被标记为error。

2. 测试结果判定

unittest.TestCase 类包含各种判定测试结果的方法。

比如上面我们使用过的“self.assertEqual('foo'.upper(), 'FOO')”。

Method Checks that New in
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 3.1
assertIsNot(a, b) a is not b 3.1
assertIsNone(x) x is None 3.1
assertIsNotNone(x) x is not None 3.1
assertIn(a, b) a in b 3.1
assertNotIn(a, b) a not in b 3.1
assertIsInstance(a, b) isinstance(a, b) 3.2
assertNotIsInstance(a, b) not isinstance(a, b) 3.2

所有的assert方法都含有一个默认参数“msg”,该参数默认值为“None”。如果给msg传值,在assert判定fail的时候,系统就会打印出msg作为fail message。

“self.assertEqual('foo'.upper(), 'FOO1',"foo.upper is not FOO1!")”

如果assert方法判定特定条件不满足,就会抛出一个异常 AssertionError,unittest执行结果就会被判定为 fail。

3. 测试用例集(TestSuite)

多个TestCase可以组成一个TestSuite 。一般实际测试都有很多个TestCase,我们需要对其进行组合,这样方便执行以及收集结果。

跑一个TestSuite ,和单独跑TestSuite里面的所有的TestCase ,结果是一样的。

多个TestSuite 也可以组成一个更大的TestSuite。

import unittest

class TestStringMethods(unittest.TestCase):
# 类内容参见上面的代码 def suite():
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_split'))
return suite if __name__ == '__main__':
print(suite())

执行结果如下:

<unittest.suite.TestSuite tests=[<__main__.TestStringMethods testMethod=test_upper>, 
<__main__.TestStringMethods testMethod=test_split>]>

可以看到suite()返回的是一个 TestSuite实例,里面只含有我们添加进去的测试用例方法。

TestSuite 主要包含4个方法:

addTest(test):添加test到TestSuite。这里的test可以是一个TestCase,也可以是一个TestSuite。

addTests(tests):添加多个test到TestSuite。这里的tests 可以是一个 TestCase列表,也可以是一个TestSuite列表。

run(result):跑TestSuite,并且收集测试结果到result。

countTestCases():返回该TestSuite说包含的所有的TestCase数目。

4. TestLoader

该类的目的就是为了更方便的整合所有testCase 为 TestSuite。

一般都不需要实例化一个TestLoader对象,可以直接通过 unittest.defaultTestLoader 来获得一个 TestLoader 实例。

该类主要包含的都是loadTest方法,就是通过各种方式来收集TestCase 。 方法返回的是一个TestSuite 实例 。

loadTestsFromTestCase(testCaseClass):通过TestCase的类名加载用例。比如 TestStringMethods 。

loadTestsFromModule(module, pattern=None):通过模块名加载用例。

loadTestsFromName(name, module=None):通过名称加载用例。该名称一般是“xxx.xxxx.xxx.xxx”的形式,可以具体到TestCase类名(比如 TestStringMethods),也可以具体到类中的方法名(比如 test_split )。

loadTestsFromNames(names, module=None):通过多个名称加载用例。类似 loadTestsFromName ,只不过这里的参数是一个集合,比如一个列表。

discover(start_dir, pattern='test*.py', top_level_dir=None):通过路径加载用例。 start_dir 一般是一个大的路径。pattern一般是具体脚本的匹配模式,默认是所有以test开头的脚本。

使用示例:

import unittest

class TestStringMethods(unittest.TestCase):
#类内容参见上面的代码 def suite():
suite = unittest.defaultTestLoader.loadTestsFromTestCase(TestStringMethods)
return suite if __name__ == '__main__':
print(suite())

输出结果如下:

<unittest.suite.TestSuite tests=[<__main__.TestStringMethods testMethod=test_isupper>, 
<__main__.TestStringMethods testMethod=test_split>,
<__main__.TestStringMethods testMethod=test_upper>]>

可以看到返回的是一个TestSuite实例。

5. TestResult

该类用来收集测试结果。所有的测试结果都可以通过TestResult获取。

import unittest

class TestStringMethods(unittest.TestCase):
#类内容参见上面的代码 def suite():
suite =unittest.defaultTestLoader.loadTestsFromTestCase(TestStringMethods)
return suite if __name__ == '__main__':
my_result=unittest.TestResult()
my_suite=suite()
my_suite.run(my_result)
print("My Result:",my_result)
print("Errors:",my_result.errors)
print("Failures:",my_result.failures)
print("Total Run case:",my_result.testsRun)

输出结果:

My Result: <unittest.result.TestResult run=3 errors=0 failures=1>
Errors: []
Failures: [(<__main__.TestStringMethods testMethod=test_upper>, 'Traceback (most recent call last):\n File "E:\\workspace\\Test\\src\\test\\test_unittest.py", line 10, in test_upper\n self.assertEqual(\'foo\'.upper(), \'FOO1\',"oooFail")\nAssertionError: \'FOO\' != \'FOO1\'\n- FOO\n+ FOO1\n? +\n : oooFail\n')]
Total Run case: 3

errors : 返回一个列表。如果测试Pass,则列表为空。不然就是所有的error集合。

failures  : 返回一个列表。如果测试Pass,则列表为空。不然就是所有的failure集合。比如上面我故意更改 test_upper的assert判定条件,导致该用例fail。这里就记录了failure的情况。

testsRun:返回一个整数。值为所有的run的测试用例数目。比如这里就是3。

TestResult 还含有一些方法,感觉主要作用就是定义自己的TestResult时候可以重写这些方法。

startTest(test) :将要执行测试用例方法的时候调用。

stopTest(test) :测试用例方法执行完毕后调用。

startTestRun() :执行第一个用例前调用。

stopTestRun() :执行最后一个用例后调用。

addError(test, err) :测试用例返回error时调用。

addFailure(test, err) :测试用例返回fail时调用。

addSuccess(test) :测试用例返回pass时调用。

6. 命令行执行

示例:

python -m unittest test_module1 test_module2
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
python -m unittest tests/test_something.py

可以采用 “python -m unittest xxxx” 的方式来执行测试用例。 xxxx可以是模块、用例类、用例类中的方法、或者文件路径。

>python -m unittest test_unittest.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s OK

如果想获取更详细的内容,可以加 -v 。

>python -m unittest -v test_unittest.py
test_isupper (tet_excel.TestStringMethods) ... ok
test_split (tet_excel.TestStringMethods) ... ok
test_upper (tet_excel.TestStringMethods) ... ok ----------------------------------------------------------------------
Ran 3 tests in 0.002s OK

也可以使用discover来自动加载测试用例。但是前提是脚本名称必须以 test开头。

discover 命令还有其他的一些使用方法,比如自定义匹配模式等等。这里不细说。

>cd project_directory

>python -m unittest discover
...
----------------------------------------------------------------------
Ran 3 tests in 0.001s OK

7. 跳过执行

如果某个测试方法不想执行,给它加上 skip()装饰器即可。

示例:

import unittest
import sys
from common import mylib class MyTestCase(unittest.TestCase): @unittest.skip("demonstrating skipping")
def test_nothing(self):
self.fail("shouldn't happen") @unittest.skipIf(mylib.__version__< 5,
"not supported in this library version")
def test_format(self):
# Tests that work for only a certain version of the library.
pass @unittest.skipUnless(sys.platform.startswith("win"), "requires Windows")
def test_windows_support(self):
# windows specific testing code
pass if __name__ == '__main__':
unittest.main(verbosity=2)

执行结果如下:

test_format (__main__.MyTestCase) ... skipped 'not supported in this library version'
test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping'
test_windows_support (__main__.MyTestCase) ... ok ----------------------------------------------------------------------
Ran 3 tests in 0.001s OK (skipped=2)

可以看到前面两个用例都被跳过了。但是因为我的环境时window的,所以第3个用例没有被跳过。

如果某个测试用例类不想执行,也可以跳过。

import unittest

@unittest.skip("showing class skipping")
class MySkippedTestCase(unittest.TestCase):
def test_not_run(self):
pass def test_not_run2(self):
pass if __name__ == '__main__':
unittest.main(verbosity=2)

执行结果如下:

test_not_run (__main__.MySkippedTestCase) ... skipped 'showing class skipping'
test_not_run2 (__main__.MySkippedTestCase) ... skipped 'showing class skipping' ----------------------------------------------------------------------
Ran 2 tests in 0.000s OK (skipped=2)

可以看到两个测试用例方法都被跳过了。

8. TestProgram

关于命令行执行的一个测试类。没看到官方文档有详细的资料,暂时不研究。

unittest笔记的更多相关文章

  1. python + unittest 做单元测试之学习笔记

    单元测试在保证开发效率.可维护性和软件质量等方面有很重要的地位,所谓的单元测试,就是对一个类,一个模块或者一个函数进行正确性检测的一种测试方式. 这里主要是就应用 python + unitest 做 ...

  2. 笔记-unittest实战

    笔记-unittest实战 1.      框架图 2.      用例 编写自己的测试用例类,继承于基类 class ApiTestCase(unittest.TestCase): setUp方法会 ...

  3. 笔记-python-standard library-26.4 unittest

    笔记-python-standard library-26.4 unittest 1.      unittest source code:Lib/unittest/__init__.py 它是pyt ...

  4. python unittest 测试笔记(二):使用Requests

    1. Requests 唯一的一个非转基因的 Python HTTP 库,人类可以安全享用.[Python Requests快速入门 :]http://cn.python-requests.org/z ...

  5. python unittest 测试笔记(一)

    测试最基本的原理就是比较预期结果是否与实际执行结果相同,如果相同则测试成功,否则测试失败. python 单元测试官方文档: [Python: 2.7] (https://docs.python.or ...

  6. python学习笔记9-单元测试unittest

    Python中有一个自带的单元测试框架是unittest模块,用它来做单元测试,它里面封装好了一些校验返回的结果方法和一些用例执行前的初始化操作. 在说unittest之前,先说几个概念: TestC ...

  7. pytest 学习笔记二:兼容unittest、执行方式、生成报告

    1.官方文档上说pytest兼容unittest时,不支持setUpModule 和 tearDownModule,但实际验证是可以的. 验证的场景是py文件中,只有一个测试类, 经验证有多个测试类, ...

  8. python学习笔记之——unittest框架

    unittest是python自带的单元测试框架,尽管其主要是为单元测试服务的,但我们也可以用它来做UI自动化测试和接口的自动化测试. unittest框架为我们编写用例提供了如下的能力 定义用例的能 ...

  9. Python+Selenium笔记(四):unittest的Test Suite(测试套件)

    (一) Test Suite测试套件 一个测试套件是多个测试或测试用例的集合,是针对被测程序的对应的功能和模块创建的一组测试,一个测试套件内的测试用例将一起执行. 应用unittest的TestSui ...

随机推荐

  1. Miller_Rabin codevs 1702 素数判定2

    /* 直接费马小定理 */ #include<iostream> #include<cstdio> #include<cstdlib> #include<ct ...

  2. css.day04

    1. box   盒子模型 <p>   <span>   <hr/>   <div> css+   div  p  span css+  xhtml b ...

  3. Linq101-CustomSequence

    using System; using System.Collections.Generic; using System.Linq; namespace Linq101 { class CustomS ...

  4. HTML5 Canvas Text实例1

    1.简单实例1 <canvas width="300" height="300" id="canvasOne" class=" ...

  5. Xcode工程添加第三方文件的详细分析 Create folder references for any added folders

    在开发iOS项目的时候需要导入第三方的库文件,但是通过Xcode导入第三方源文件的时候会提示一些信息,不知所以然. 现在看到的文档都是针对Xcode3的,针对Xcode4的说明很少,现在分享出来. 官 ...

  6. 05DotNet基本常用类库

    1.String成员方法(常用) bool Contains(String str);判断字符串对象是否包含给定的字符串; bool StartsWith(String str);判断字符串对象是否以 ...

  7. PHP PDO 简单登陆操作

    用PHP做出一个简单的登陆操作,确实很简单,下面就让我给大家简单的介绍一下PDO做出一个登陆界面操作的过程,因为也是初学乍练,不足之处请大家包涵. 首先,首先还要建一个表,在MySQL中建表,核心代码 ...

  8. Animator Override Controllers 学习及性能测试

    本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/Unity_AnimatorOverrideContorller.html  The ...

  9. Tomcat安装阿里云免费证书

    安装证书 Tomcat支持JKS格式证书,从Tomcat7开始也支持PFX格式证书,两种证书格式任选其一.下载包中包含PFX格式证书和密码文件. 1.PFX证书安装 找到安装 Tomcat 目录下该文 ...

  10. Js监控回车事件

    标题通俗的说,也就是绑定当用户按下回车键要执行的事件. 下面,入正题. 第一步,先编写简单的页面代码,这里我们只需要一个按钮就足够了.当然,还有按钮事件. <html> <head& ...