笔记-python-standard library-26.4 unittest

1.      unittest

source code:Lib/unittest/__init__.py

它是python自带的单元测试框架,封装好了一些校验返回的结果方法和一些用例执行前的初始化操作。

在开始之前,有几个概念:

  1. test fixture

它表示一个或多个测试用例,还有相关的清理动作;

  1. test case:测试用例,unittest提供了一个基类,TestCase;
  2. test suite:测试用例集合,也可包含test suite,
  3. test runner:它是一个执行测试并输出测试结果的组件。

1.1.    test case和更高级别的用例集合

单元测试的最小单元是测试用例,典型的test case如下:

import unittest

class DefaultWidgetSizeTestCase(unittest.TestCase):

def test_default_widget_size(self):

widget = Widget('The widget')

self.assertEqual(widget.size(), (50, 50))

测试用例应该是完全独立的。

测试用例可以有多个,使用setUp()来安装;

运行各种测试的顺序是通过根据字符串的内置顺序对测试方法名称进行排序来确定的。

import unittest

class WidgetTestCase(unittest.TestCase):

def setUp(self):

self.widget = Widget('The widget')

def tearDown(self):

self.widget.dispose()

tearDown()则是用于测试后环境清理。如果setUp() succeeded,tearDown() will be run whether the test method succeeded or not.

上面的代码段被称为fixture。

测试用例会很多,unittest为此提供的更高级别的抽象实现;suite

def suite():

suite = unittest.TestSuite()

suite.addTest(WidgetTestCase('test_default_widget_size'))

suite.addTest(WidgetTestCase('test_widget_resize'))

return suite

if __name__ == '__main__':

runner = unittest.TextTestRunner()

runner.run(suite())

这样最重要的益处是可以将用例和测试代码分开。

1.2.    skipping tests and expected failures

Unittest支持跳过测试用例和预期失败处理。

跳过测试用例使用skip() decorator,或者其变型。

class MyTestCase(unittest.TestCase):

@unittest.skip("demonstrating skipping")

def test_nothing(self):

self.fail("shouldn't happen")

@unittest.skipIf(mylib.__version__ < (1, 3),

"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

输出如下:

test_format (__main__.MyTestCase) ... skipped 'not supported in this library version'

test_nothing (__main__.MyTestCase) ... skipped 'demonstrating skipping'

test_windows_support (__main__.MyTestCase) ... skipped 'requires Windows'

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

Ran 3 tests in 0.005s

OK (skipped=3)

Classes can be skipped just like methods:

@unittest.skip("showing class skipping")

class MySkippedTestCase(unittest.TestCase):

def test_not_run(self):

pass

Expected failures use the expectedFailure() decorator.

class ExpectedFailureTestCase(unittest.TestCase):

@unittest.expectedFailure

def test_fail(self):

self.assertEqual(1, 0, "broken")

1.2.1.   skip装饰器及其变型

@unittest.skip(reason)

Unconditionally skip the decorated test. reason should describe why the test is being skipped.

@unittest.skipIf(condition, reason)

Skip the decorated test if condition is true.

@unittest.skipUnless(condition, reason)

Skip the decorated test unless condition is true.

@unittest.expectedFailure

Mark the test as an expected failure. If the test fails when run, the test is not counted as a failure.

exception unittest.SkipTest(reason)

This exception is raised to skip a test.

1.3.    class and functions

This section describes in depth the API of unittest.

1.3.1.   test case

class unittest.TestCase(methodName='runTest')

常用的也就setUp(),tearDown()了。

TestCase提供了一些assert方法

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

下面还有很多方法,使用的时候可以查,这里不多写。

1.3.2.   group tests

class unittest.TestSuite(tests=())

  1. addTest(test)

Add a TestCase or TestSuite to the suite.

  1. addTests(tests)

Add all the tests from an iterable of TestCase and TestSuite instances to this test suite.

This is equivalent to iterating over tests, calling addTest() for each element.

  1. countTestCases()

Return the number of tests represented by this test object, including all individual tests and sub-suites.

1.3.3.   loading and running tests

class unittest.TestLoader

The TestLoader class is used to create test suites from classes and modules. Normally, there is no need to create an instance of this class; the unittest module provides an instance that can be shared as unittest.defaultTestLoader. Using a subclass or instance, however, allows customization of some configurable properties.

class unittest.TestResult

This class is used to compile information about which tests have succeeded and which have failed.

有一个需要注意的

unittest.main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None)

A command-line program that loads a set of tests from module and runs them; this is primarily for making test modules conveniently executable. The simplest use for this function is to include the following line at the end of a test script:

if __name__ == '__main__':

unittest.main()

You can run tests with more detailed information by passing in the verbosity argument:

if __name__ == '__main__':

unittest.main(verbosity=2)

一般情况下都会使用main,这时可以通过verbosity参数指定结果的详细程度。

另一个常用的是

class unittest.TextTestRunner(stream=None, descriptions=True, verbosity=1, failfast=False, buffer=False, resultclass=None, warnings=None, *, tb_locals=False)

A basic test runner implementation that outputs results to a stream. If stream is None, the default, sys.stderr is used as the output stream. This class has a few configurable parameters, but is essentially very simple. Graphical applications which run test suites should provide alternate implementations. Such implementations should accept **kwargs as the interface to construct runners changes when features are added to unittest.

基本的runner执行函数,输出指向一个stream。常用于输出测试结果到文件中。

1.4.    Class and Module Fixtures

Class and module level fixtures are implemented in TestSuite. When the test suite encounters a test from a new class then tearDownClass() from the previous class (if there is one) is called, followed by setUpClass() from the new class.

1.4.1.    setUpClass and tearDownClass

These must be implemented as class methods:

import unittest
 
class Test(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._connection = createExpensiveConnectionObject()
 
    @classmethod
    def tearDownClass(cls):
        cls._connection.destroy()

2.      案例实测

2.1.    案例1

基本版测试

import unittest

class MyTest(unittest.TestCase):  # 继承unittest.TestCase

def tearDown(self):

# 每个测试用例执行之后做操作

print('tear down')

def setUp(self):

# 每个测试用例执行之前做操作

print('set up')

@classmethod

def tearDownClass(self):

# 必须使用 @ classmethod装饰器, 所有test运行完后运行一次

print('tear down class')

@classmethod

def setUpClass(self):

# 必须使用@classmethod 装饰器,所有test运行前运行一次

print('set up class')

def test_a_run(self):

self.assertEqual(1, 1)  # 测试用例

def test_b_run(self):

self.assertEqual(2, 2)  # 测试用例

if __name__ == '__main__':

unittest.main()#运行所有的测试用例

输出:

===== RESTART: E:\python\person_code\python libs tests\unittest_test1.py =====

set up class

set up

tear down

.set up

tear down

.tear down class

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

Ran 2 tests in 0.086s

OK

>>>

2.2.    测试结果输出到文件

#coding:utf-8

import unittest

from unittest_test1 import MyTest

if __name__ == '__main__':

suite = unittest.TestSuite()

tests = [MyTest("test_a_run"), MyTest("test_b_run")]

suite.addTests(tests)

with open('UnittestTextReport.txt', 'a') as  f:

runner = unittest.TextTestRunner(stream=f, verbosity=2)

runner.run(suite)

输出:

=========== RESTART: E:\python\person_code\python libs tests\d.py ===========

set up class

set up

tear down

set up

tear down

tear down class

>>>

3.      扩展

3.1.    测试结果美化

txt格式的文本执行报告过于简陋,这里学习一下借助HTMLTestRunner生成HTML报告。首先需要下载HTMLTestRunner.py,并放到当前目录下,或者python目录下的Lib中,就可以导入运行了。

下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

当然,测试代码需要改一部分

#coding:utf-8

import unittest

from unittest_test1 import MyTest

from HTMLTestRunner import HTMLTestRunner

if __name__ == '__main__':

suite = unittest.TestSuite()

tests = [MyTest("test_a_run"), MyTest("test_b_run")]

suite.addTests(tests)

with open('UnittestTextReport.html', 'a') as  f:

runner = HTMLTestRunner(stream=f,

title = 'MathFunc Test Report',

description='generated by HTMLTestRunner.',

verbosity=2

)

runner.run(suite)

输出:

3.1.1.   问题

在使用HTMLTestRunner时报错:

ModuleNotFoundError: No module named 'StringIO'

原因为python3中StringIO已改到io中

需要对HTMLTestRunner作如下改变:

第94行,将import StringIO修改成import io as StringIO

第539行,将self.outputBuffer = StringIO.StringIO()修改成self.outputBuffer = io.StringIO()

第642行,将if not rmap.has_key(cls):修改成if not cls in rmap:

第766行,将uo = o.decode('latin-1')修改成uo = e

第775行,将ue = e.decode('latin-1')修改成ue = e

第631行,将print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)修改成print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime))

第689行 self.stream.write(output.encode(‘utf-8’))改为self.stream.write(output)

4.      总结

1、unittest是python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架。

2、unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。

3、一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。

4、verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。

5、可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。

6、用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境

7、我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法。

8、参数中加stream,可以将报告输出到文件:可以用TextTestRunner输出txt报告,以及可以用HTMLTestRunner输出html报告。

最新文章

  1. IOS 微信 6.5.2 自动播放音乐 解决方案
  2. tomcat 和servlet之间的关系
  3. Tcpdump的详细用法
  4. KVC与KVO
  5. The storage wars: Shadow Paging, Log Structured Merge and Write Ahead Logging
  6. Codeforces Round #230 (Div. 2) 解题报告
  7. iOS 进阶 第十天(0410)
  8. mysql备份恢复数据库据/表
  9. Android仿腾讯应用宝 应用市场,下载界面, 有了进展button
  10. SharePoint : 使用SPQuery对象时要注意的事项
  11. Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
  12. &gt; library(&#39;ggplot2&#39;) Error in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]) : 不存在叫‘colorspace’这个名字的程辑包
  13. cadence分列元件原理图库的设计
  14. DAX/PowerBI系列 - 查询参数用法详解(Query Parameter)
  15. 【XSY2484】mex 离散化 线段树
  16. THINKPHP5近期暴露的漏洞
  17. C语言编程比赛WBS
  18. hdu 3910 Liang Guo Sha
  19. 11.2.0.3 RAC(VCS)节点crash以及hang的问题分析
  20. Hadoop HBase概念学习系列之HBase里的宽表设计概念(表设计)(二十七)

热门文章

  1. spring笔记4-事务管理
  2. 一次ddos攻击
  3. Ajax使用 初始化数据 + mvc
  4. org.springframework.beans.MethodInvocationException: Property &#39;cacheManager&#39; threw exception; nested exception is org.apache.shiro.cache.CacheException: net.sf.ehcache.CacheException: Caches cannot be
  5. 笨办法学Python(三十六)
  6. C++学习之显式类型转换与运行时类型识别RTTI
  7. 【CCPC-Wannafly Winter Camp Day4 (Div1) I】咆咆咆哮(三分+贪心)
  8. HDU(3560)成环,并查集
  9. 课程设计__继承与派生,重载&lt;&lt;
  10. Android检查更新(是否强制更新)