unittest笔记

背景

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')”。

MethodChecks thatNew in
assertEqual(a, b)== b 
assertNotEqual(a, b)!= b 
assertTrue(x)bool(x) is True 
assertFalse(x)bool(x) is False 
assertIs(a, b)is b3.1
assertIsNot(a, b)is not b3.1
assertIsNone(x)is None3.1
assertIsNotNone(x)is not None3.1
assertIn(a, b)in b3.1
assertNotIn(a, b)not in b3.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

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

转载于:https://www.cnblogs.com/miniren/p/4995239.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值