Python单元测试框架 unittest详解
一 整体结构概览
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) >
看下面的例子(创建一个测试类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详解的更多相关文章
- Python单元测试框架unittest使用方法讲解
这篇文章主要介绍了Python单元测试框架unittest使用方法讲解,本文讲解了unittest概述.命令行接口.测试案例自动搜索.创建测试代码.构建测试套件方法等内容,需要的朋友可以参考下 概 ...
- Python单元测试框架unittest之深入学习
前言 前几篇文章该要地介绍了python单元测试框架unittest的使用,本篇文章系统介绍unittest框架. 一.unittest核心工作原理 unittest中最核心的四个概念是:test c ...
- Python单元测试框架unittest之单用例管理(一)
一.概述 本文介绍python的单元测试框架unittest,unittest原名为PyUnit,是由java的JUnit衍生而来,这是Python自带的标准模块unittest.unittest是基 ...
- Python单元测试框架unittest
学习接口自动化测试时接触了unittest单元测试框架,学习时参照了虫师编写的<selenium2自动化测试实战>,个人觉得里面讲的例子还比较容易理解的. 一.基础 1.main()和框架 ...
- Python单元测试框架unittest重要属性 与 用例编写思路
前言 本文为转载,原文地址作者列举python unittest这个测试框架的主要属性和 测试用例思路 unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行, ...
- Python 定时任务框架 APScheduler 详解
APScheduler 最近想写个任务调度程序,于是研究了下 Python 中的任务调度工具,比较有名的是:Celery,RQ,APScheduler. Celery:非常强大的分布式任务调度框架 R ...
- python单元测试框架-unittest(一)
简介 unittest单元测试框架不仅可以适用于单元测试,还可以使用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果. ...
- javascript单元测试框架mochajs详解
关于单元测试的想法 对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程.在github上看到牛逼的javascript开 ...
- javascript单元测试框架mochajs详解(转载)
章节目录 关于单元测试的想法 mocha单元测试框架简介 安装mocha 一个简单的例子 mocha支持的断言模块 同步代码测试 异步代码测试 promise代码测试 不建议使用箭头函数 钩子函数 钩 ...
随机推荐
- js控制随机数生成概率代码实例
基本思路:把Math.random()js随机数生成的数看着百分比,然后定义每个整数值取值范围. 具体内容如下,供大家参考 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ...
- Dev、GridControl的模糊查询
/// <summary> /// 设置girid为每一列都模糊搜索 /// </summary> /// <param name="gdv"> ...
- angular 用拦截器统一处理http请求和响应 比如加token
想使用angularjs里的htpp向后台发送请求,现在有个用户唯一识别的token想要放到headers里面去,也就是{headres:{'token':1}} index.html里引入以下js: ...
- angular分页插件tm.pagination 解决触发二次请求的问题
angular分页插件tm.pagination(解决触发二次请求的问题) DEMO: http://jqvue.com/demo/tm.pagination/index.html#?current ...
- sublime text2 中标签高亮效果BracketHighlighter插件
1.打开package Control,选择install Package 2.输入BracketHighlighter,回车 3.这样该插件会自动安装,安装后所有的提示高亮都是白色或没有提示.按 p ...
- 2018-10-08 Java源码英翻中进展-内测上线
创建了一个子域名: http://translate.codeinchinese.com/ 欢迎试用, 如有建议/发现问题欢迎在此拍砖: program-in-chinese/code_transla ...
- SAP MM 物料主数据MRP2 视图’Minimum Lot Size’字段
SAP MM 物料主数据MRP2 视图’Minimum Lot Size’字段 如下物料号,MRP2视图中,维护了最小采购量为500. MRP type : PD Lot size: EX Minim ...
- LNMP的配置与优化
一.LNMP的下载 LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RadHat/Fedora.Debian/Ubuntu/Raspbian/Deepin VPS或独立主机安 ...
- Javascript 对象 - 日期对象
日期对象 在JavaScript中提供了Data对象,用于处理和日期有关的内容.通过Data对象可以获取系统时间.设置时间等.Data对象也具有prototype和constructor属性. 1创建 ...
- web前端(2)—— 前端技术介绍
前端技术 前文了解了什么是前端,那么前端技术到底有哪些呢?最核心的就这三个: html/html5 css/css3 javascript 什么是HTML HyperText Markup Langu ...