一 整体结构概览

unittest原名为PyUnit,是由java的JUnit衍生而来。对于单元测试,需要设置预先条件,对比预期结果和实际结果。

  • TestCase :通过继承TestCase类,我们可以创建一个test,或者一组tests. 一个TestCase的实例就是一个测试用例,是一个完整的测试流程,包括测试前准备环境的搭建(setUp),实现测试过程的代码(run),测试后环境的还原(tearDown).
  • Test Suites : 测试套件, 把多个测试用例集合在一起来执行。可以通过addTest加载TestCase到Test Suite中,从而返回一个TestSuite实例。
  • Test Fixtures : setup + test case + teardown结构 , 对一个测试用例环境的搭建和销毁。通过覆盖TestCase的setUp()和tearDown()方法来实现。tearDown()为下一个测试用例提供一个干净的环境。
  • Test Runner : 测试的执行,通过TextTestRunner类提供的run()方法来执行Test Suite/TestCase。Test Runner可以使用图形界面,文本界面,或者返回一个特殊的值的方式来表示测试执行的结果。

所有的测试函数以test开头,test_XXX。

简单的示例:
# -*-coding:utf--*-
import unittest # 被测试的函数,姓名格式化输出
def get_formatted_name(first,last):
"""Generate a neatly formatted full name."""
full_name = first + " " + last
return full_name.title() class NameTestCase(unittest.TestCase):
# 从unitteset的包中继承TestCase这个类,这样Python能够识别你编写的测试
def test_first_last_name(self):
"""
测试用例:所有以test开头的
"""
formatted_name = get_formatted_name("jian","yu")
self.assertEqual(formatted_name,"Jia Yu") if __name__ == "__main__":
unittest.main()

如果被测试的函数(测试用例)本身有错误

会报E

如果 测试用例本身没错 而在判断比对 self.assertEqual 的时候 不一致 则会报F

以上是函数的测试,类的测试与函数的测试及其相似

 import unittest

 #-*-coding:utf--*-
class AnonymousSurvey():
"""收集匿名调查问卷答案"""
def __init__(self,question=None):
"""
Args:
question:restore the answers for question
Return:
None
"""
self.question = question
self.responses = [] def show_question(self):
"""
print question
"""
print(self.question) def store_response(self,new_response):
self.responses.append(new_response) def show_results(self):
"""
显示收集到的所有答案
"""
print("Survey Results")
for response in self.responses:
print("-"+response) class TestAnonymousSurvey(unittest.TestCase):
"""
A test according to AnonymousSurvey
"""
def test_store_single_response(self):
question = "what lauguage did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response("Chinese")
self.assertIn("Chinese",my_survey.responses) def test_store_multi_responses(self):
question = "what lauguage did you first learn to speak?"
my_survey = AnonymousSurvey(question)
responses = ["Chinese","English","French","German"]
for response in responses:
my_survey.store_response(response)
for response in responses:
self.assertIn(response,my_survey.responses) if __name__ == "__main__":
unittest.main()

这里可以看到 两个测试样例有一定的重复部分,可以利用unittest.TestCase类方法setUp(),作为共享变量初始化,Python运行TestCase的类会首先运行setUp() (相当于unittest.TestCase版的def __init__())

#-*-coding:utf--*-
import unittest
class AnonymousSurvey():
"""收集匿名调查问卷答案"""
def __init__(self,question=None):
"""
Args:
question:restore the answers for question
Return:
None
"""
self.question = question
self.responses = [] def show_question(self):
"""
print question
"""
print(self.question) def store_response(self,new_response):
self.responses.append(new_response) def show_results(self):
"""
显示收集到的所有答案
"""
print("Survey Results")
for response in self.responses:
print("-"+response) class TestAnonymousSurvey(unittest.TestCase):
"""
A test according to AnonymousSurvey
"""
def setUp(self):
question = "what lauguage did you first learn to speak?"
self.my_survey = AnonymousSurvey(question)
self.responses = ["Chinese","English","French","German"] def test_store_single_response(self):
self.my_survey.store_response("Chinese")
self.assertIn("Chinese",self.my_survey.responses) def test_store_multi_responses(self):
for response in self.responses:
self.my_survey.store_response(response)
for response in self.responses:
self.assertIn(response,self.my_survey.responses) if __name__ == "__main__":
unittest.main()

但值得注意的时 setUp()内的my_survey和responses都需要增加前缀self(意为储存在类属性中),

因此可在这个类的任何地方使用

否则无法传递

二 命令行

  • 从命令行中可以运行单元测试的模块,类,甚至单独的测试方法。
 python -m unittest test_module1 test_module2
#同时测试多个module
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
  • 显示更详细的测试结果的说明使用 [-v] flag:
 python -m unittest -v test_module
  • 查看所有的命令行选项使用命令
 python -m unittest -h

三 TestCase

  • Testcase类  <形如class xxxTestCase(unittest.TestCase)  >
TestCase的实例是最小的可测试单元。 testcase 是由unittest的TestCase类的实例表示的。要编写自己的测试用例必须继承TestCase类,或者使用FunctionTestCase。且Testcase类提供了各种assert的方法来检测预期结果和实际结果。
看下面的例子(创建一个测试类DefaultWidgetSizeTestCase):
import unittest
class DefaultWidgetSizeTestCase(unittest.TestCase):
#unittest.TestCase表示某个测试函数
  def runTest(self):
    widget = Widget('The widget')
    self.assertEqual(widget.size(), (, ), 'incorrect default size')

创建实例建立这样一个测试用例的一个实例,使用该类的构造函数,且不带参数(这样会执行所有的测试方法):
testCase = DefaultWidgetSizeTestCase()

我们也可以创建多个实例,且每个实例之间都是独立的。当我们需要对不同的实例执行不同的测试方法时,我们可以将要执行的测试用例方法在创建实例时通过类参数传入。
建了两个WidgetTestCase的实例,每个实例只运行WidgetTestCase类中的一个测试方法(通过参数传入)
defaultSizeTestCase = WidgetTestCase('test_default_size')
resizeTestCase = WidgetTestCase('test_resize')

常用断言方法 <查看官方文档>
unittest库提供了很多实用方法来检测程序运行的结果和预期。包括三种类型的方法,每一种都覆盖了典型的类型

  • 检测元素是否相等:assertEqual(a,b [,msg]):
assertEqual(element.text, "")
assertNotEqual(a,b [,smg]):检测a!==b.
  • 检测表达式是否为Ture,或者 False:
assertTrue(x [,msg])
assertFalse(x [,msg])
  • 检测异常assertRaises(exc, fun, *args, **kwds)
assertRaiseRegexp(exc, r, fun, *args, **kwds)
  • 逻辑运算
assertGreater(a, b) # 检测a > b.
assertGreaterEqual(a ,b) # 检测a >= b.
assertLess(a, b) #检测a < b.
assertLessEqual(a, b) #检测a <= b.="" <="" code=""></=>
  • 正则表达式,检测正则是否匹配给定的text
assertRegexpMatches(s, r) #检测r.search(s).
assertNotRegexpMatches(s, r) #检测not r.search(s).

四 Test fixtures

方法固定装置:
如果要对一个模块中的每一个测试函数都做同样的初始化操作和结尾清除等操作,那么创建n个测试用例就得写n遍一样的代码,为了减少重复的代码,可以使用下面两个函数:

setUp(): 每次执行测试用例之前调用。无参数,无返回值。该方法抛出的异常都视为error,而不是测试不通过。没有默认的实现。

tearDown(): 每次执行测试用例之后调用。无参数,无返回值。测试方法抛出异常,该方法也正常调用,该方法抛出的异常都视为error,而不是测试不通过。只用setUp()调用成功,该方法才会被调用。没有默认的实现。通过setup 和 tesrDown组装一个module成为一个固定的测试装置。注意:如果setup运行抛出错误,则测试用例代码则不会执行。但是,如果setpu执行成功,不管测试用例是否执行成功都会执行teardown。

Class固定装置:
必须为类实现

setUpClass():一个类方法在单个类测试之前运行。setUpClass作为唯一的参数被调用时,必须使用classmethod()作为装饰器。

tearDownClass():一个类方法在单个类测试之后运行。setUpClass作为唯一的参数被调用时,必须使用classmethod()作为装饰器。

import unittest
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls): #这里的cls是当前类的对象
cls._connection = createExpensiveConnectionObject()
@classmethod
def tearDownClass(cls):
cls._connection.destroy()

五 使用Text Suite组织测试代码

unittest.TestSuite(tests=())

该类聚合测试用例和测试套件,运行一个TestSuite实例遍历套件,和单独运行每个testcase是相同的。TestSuite对象的行为就像TestCase对象,除了他们不实现一个测试。
一些方法可以将testcase添加到TestSuite实例:

addTest(test):Add a TestCase or TestSuite to the suite.

addTests(tests):添加所有的tests从可迭代的TestCase和TestSuite实例测试套件。这相当于迭代调用addTest()来添加每个元素。

根据不同的业务可能需要在不同的module中选择某一个或者几个测试用例,此时可以根据每个测试实例的特征对测试方法打包:
widgetTestSuite = unittest.TestSuite()
#创建一个测试套件实例
widgetTestSuite.addTest(WidgetTestCase('test_default_size'))
#添加测试用例到套件,抽取WidgetTestCase类中的test_default_size测试用例添加到
testsuitewidgetTestSuite.addTest(WidgetTestCase('test_resize'))
#添加测试用例到套件,抽取WidgetTestCase类中的test_resize测试用例添加到testsuite

可以返回该测试套件的get入口:
def suite():
suite = unittest.TestSuite()
suite.addTest(WidgetTestCase('test_default_size'))
suite.addTest(WidgetTestCase('test_resize'))
return suite

或者更简洁的写法:
def suite():
tests = ['test_default_size', 'test_resize']
return unittest.TestSuite(map(WidgetTestCase, tests))

测试套件中也可以包含测试套件:
suite1 = module1.TheTestSuite()
suite2 = module2.TheTestSuite()
alltests = unittest.TestSuite([suite1, suite2])

使用TestLoader
lass unittest.TestLoader

TestLoader 用来从clases和modules创建test suites,通常也需要创建一个该类的实例,unittest模块提供了一个实例,可以作为unittest.defaultTestLoader共享。使用一个子类或实例,允许定制可配置属性。该类有以下方法:loadTestsFromTestCase(testCaseClass):

loadTestsFromModule(module):返回一个给定的模块中所有测试用例,打包成一个套件返回。该类创建一个testsuites然后加载一个module并执行其中所有的测试用例,执行的顺序是根据测试用例的名称来的。
suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
#执行WidgetTestCase中所有的测试用例

你可以将测试用例和测试套件放在一个module中,最好是分开放置,方便重构管理,如果测试策略改变了,也方便维护。

六 跳过测试和预期的失败

Unittest支持跳过单个的测试方法甚至整个类的测试。使用 skip() decorator来设置特定跳过的条件,如指定操作系统不执行该测试。

执行的时候如果满足跳过条件,控制台会将后面的说明打印出来,并跳过该测试用例。跳过类也是相似的写法。也可以自定义skipping装饰器。

定义预期的失败使用unittest.expectedFailure(),运行时 ,如果测试失败,测试不算作失败。

class TestDtuOp(unittest.TestCase):
def setUp(self):
print("\n=======================================") def tearDown(self):
pass @tt.show_test_case_name
def test_upper(self):
""" This test should be passed. """
self.assertEqual('foo'.upper(), 'FOO') def test_error(self):
""" This test should be marked as error one. """
raise ValueError def test_fail(self):
""" This test should fail. """
self.assertEqual(1, 2) @unittest.skip("This is a skipped test.")
def test_skip(self):
""" This test should be skipped. """
pass @unittest.expectedFailure
def test_expectedFailure(self):
""" This test should be expectedFailure. """
pass

七 使用HTMLTestRunner生成报告

unittest本身并不具备这个功能,需要使用HTMLTestRunner库使用步骤 (这里暂时不进行拓展)

Python单元测试框架 unittest详解的更多相关文章

  1. Python单元测试框架unittest使用方法讲解

    这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下   概 ...

  2. Python单元测试框架unittest之深入学习

    前言 前几篇文章该要地介绍了python单元测试框架unittest的使用,本篇文章系统介绍unittest框架. 一.unittest核心工作原理 unittest中最核心的四个概念是:test c ...

  3. Python单元测试框架unittest之单用例管理(一)

    一.概述 本文介绍python的单元测试框架unittest,unittest原名为PyUnit,是由java的JUnit衍生而来,这是Python自带的标准模块unittest.unittest是基 ...

  4. Python单元测试框架unittest

    学习接口自动化测试时接触了unittest单元测试框架,学习时参照了虫师编写的<selenium2自动化测试实战>,个人觉得里面讲的例子还比较容易理解的. 一.基础 1.main()和框架 ...

  5. Python单元测试框架unittest重要属性 与 用例编写思路

    前言 本文为转载,原文地址作者列举python unittest这个测试框架的主要属性和 测试用例思路 unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行, ...

  6. Python 定时任务框架 APScheduler 详解

    APScheduler 最近想写个任务调度程序,于是研究了下 Python 中的任务调度工具,比较有名的是:Celery,RQ,APScheduler. Celery:非常强大的分布式任务调度框架 R ...

  7. python单元测试框架-unittest(一)

    简介 unittest单元测试框架不仅可以适用于单元测试,还可以使用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果. ...

  8. javascript单元测试框架mochajs详解

    关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...

  9. javascript单元测试框架mochajs详解(转载)

    章节目录 关于单元测试的想法 mocha单元测试框架简介 安装mocha 一个简单的例子 mocha支持的断言模块 同步代码测试 异步代码测试 promise代码测试 不建议使用箭头函数 钩子函数 钩 ...

随机推荐

  1. 3. mysql性能分析

    一.mysql query optimizer 1. mysql 中有专门负责优化 select 语句的优化器模块,主要功能:通过计算分析系统中收集的统计信息,为客户端的 Query 提供他认为最优的 ...

  2. RNP项目遇到的坑

    1.nginx问题 和前端约定了在header中存放登录态k-v,选择的key是带下划线的. nginx 默认会丢弃带下划线的 header. 设置 underscores_in_headers on ...

  3. 2018-08-14 中文代码之Spring Boot实现简单REST服务

    最终目标详见: 参考MSDN,试搞.NET类库标识符的翻译版 · Issue #54 · program-in-chinese/overview 此文仅为技术探索+原型搭建的第一小步. 源码库: 演示 ...

  4. OSGI企业应用开发(十五)基于Spring、Mybatis、Spring MVC实现一个登录应用

    前面文章中,我们已经完成了OSGI应用中Spring.Mybatis.Spring MVC的整合,本篇文章我们就在这个基础上来完成一个简单的登录应用,其中用户名和密码需要从数据库中查询. 前面文章中, ...

  5. HTML5 & CSS3初学者指南(4) – Canvas使用

    介绍 传统的HTML主要用于文本的创建,可以通过<img>标签插入图像,动画的实现则需要第三方插件.在这方面,传统的HTML极其缺乏满足现代网页多媒体需求的能力.HTML5的到来,带来了新 ...

  6. Node.js学习起步

    Node.js学习: 简单的说 Node.js 就是运行在服务端的 JavaScript.Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台.Node.js是一个事件驱 ...

  7. Kotlin入门教程——目录索引

    Kotlin是谷歌官方认可的Android开发语言,Android Studio从3.0版本开始就内置了Kotlin,所以未来在App开发中Kotlin取代Java是大势所趋,就像当初Android ...

  8. leetcode-26.删除重复数组中的重复项

    leetcode-26.删除重复数组中的重复项 题意 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数 ...

  9. 深圳市共创力推出《以用户为中心的设计UCD方法与实战》课程!

    以用户为中心的设计(UCD)方法与实战 课程特色 现在以市场为中心.科技为基础.体验为卖点的商业社会里,用户体验是赢得用户青睐的关键特性.苹果.google.腾讯等顶级企业的成功充分说明了这一点.如何 ...

  10. Python MySQL事务、引擎、索引及第三方库sqlalchemy

    本节内容 1.数据库介绍2.事务3.引擎4.索引5.ORM sqlalchemy 1.数据库介绍 什么是数据库? 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,每个数据库都有一 ...