笔记-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报告。

笔记-python-standard library-26.4 unittest的更多相关文章

  1. The Python Standard Library

    The Python Standard Library¶ While The Python Language Reference describes the exact syntax and sema ...

  2. Python Standard Library

    Python Standard Library "We'd like to pretend that 'Fredrik' is a role, but even hundreds of vo ...

  3. Python语言中对于json数据的编解码——Usage of json a Python standard library

    一.概述 1.1 关于JSON数据格式 JSON (JavaScript Object Notation), specified by RFC 7159 (which obsoletes RFC 46 ...

  4. 《The Python Standard Library》——http模块阅读笔记1

    官方文档:https://docs.python.org/3.5/library/http.html 偷个懒,截图如下: 即,http客户端编程一般用urllib.request库(主要用于“在这复杂 ...

  5. 《The Python Standard Library》——http模块阅读笔记2

    http.server是用来构建HTTP服务器(web服务器)的模块,定义了许多相关的类. 创建及运行服务器的代码一般为: def run(server_class=HTTPServer, handl ...

  6. 《The Python Standard Library》——http模块阅读笔记3

    http.cookies — HTTP state management http.cookies模块定义了一系列类来抽象cookies这个概念,一个HTTP状态管理机制.该模块支持string-on ...

  7. Python Standard Library 学习(一) -- Built-in Functions 内建函数

    内建函数列表 Built-in Functions abs() divmod() input() open() staticmethod() all() enumerate() int() ord() ...

  8. [译]The Python Tutorial#10. Brief Tour of the Standard Library

    [译]The Python Tutorial#Brief Tour of the Standard Library 10.1 Operating System Interface os模块为与操作系统 ...

  9. C++11新特性——The C++ standard library, 2nd Edition 笔记(一)

    前言 这是我阅读<The C++ standard library, 2nd Edition>所做读书笔记的第一篇.这个系列基本上会以一章一篇的节奏来写,少数以C++03为主的章节会和其它 ...

  10. [译]The Python Tutorial#11. Brief Tour of the Standard Library — Part II

    [译]The Python Tutorial#Brief Tour of the Standard Library - Part II 第二部分介绍更多满足专业编程需求的高级模块,这些模块在小型脚本中 ...

随机推荐

  1. centos7服务器搭建javaweb运行环境及代码部署

    之前在一直在学习java web终于写完了第一个小demo,于是在阿里云上买了一个服务器,开始了配置服务器环境的踩坑之旅.... ps:本文不讨论服务器配置的具体步骤,网上都很多,按部就班就是,本文主 ...

  2. iDempiere 使用指南 生产插件(Manufacturing)安装过程

    Created by 蓝色布鲁斯,QQ32876341,blog http://www.cnblogs.com/zzyan/ iDempiere官方中文wiki主页 http://wiki.idemp ...

  3. Azure 5 月新公布(二)

    Azure 5 月新发布(二):CDN 图片处理功能, CDN Restful API, 新版 CDN 管理门户, 计量名称变更延期  Azure CDN 图片处理功能开放公共预览版 Azure CD ...

  4. Eclipse导入web项目后,run列表中没有run on server?

    Eclipse导入web项目,没有run列表中run on server? 首先确保正确安装Tomcat和JDK .找到对于web项目的文件夹,打开文件夹下.project文件 <?xml ve ...

  5. git 因线上分支名重复导致无法拉取代码

    有时 git pull 或 git fetch 时发现 git 报了个异常,说法像是无法将线上某个分支与本地分支合并,由于分支是...(很长的hash)但是分支却是...(很长的hash) 仔细查查后 ...

  6. 【js基础修炼之路】— 深入浅出理解闭包

    之前对于闭包的理解只是很肤浅的,只是浮于表面,这次深究了一下闭包,下面是我对闭包的理解. 什么是闭包? 引用高程里的话 => 闭包就是有权访问另一个作用域中变量的函数,闭包是由函数以及创建该函数 ...

  7. 页面文本超出后CSS实现隐藏的方法

    text-overflow: ellipsis !important; white-space: nowrap !important; overflow: hidden !important; dis ...

  8. 前端js限制上传文件类型及大小(1)

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  9. NOIP2018学军中学游记(11.09~11.11)

    前言 这篇博客记录的是我在\(NOIP2018\)提高组比赛中的经历. 这一次的\(NOIP\)是在学军中学举办的, 莫名感到一阵慌张. 但愿能有一个好成绩,不然就要\(AFO\)了... ... 说 ...

  10. 零基础Centos6搭建Git服务器,及常见问题解决

    1.编译安装git 2.1 服务器端: #yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel perl- ...