Python中的单元测试模块Unittest快速入门
前言
为什么需要单元测试?
如果没有单元测试,我们会遇到这种情况:已有的健康运行的代码在经过改动之后,我们无法得知改动之后是否引入了Bug。如果有单元测试的话,只要单元测试全部通过,我们就可以保证没有Bug被引入。因此,单元测试是保证软件工程质量的一个很重要的方面。
Python中的单元测试
Python最强大的地方在于,开发效率高,并且有丰富的Package,避免重复造轮子。那么Python中的Unittest模块有很丰富的功能提供给我们调用:完整的测试框架,丰富的拓展,比如我们可以设置测试之前的一些初始化工作,比如链接数据库等,规划测试集中有哪些测试用例需要跳过,以及跳过的原因。
Unittest中几个类(Class)的基本概念
TestCase 是我们要写的具体的测试用例
TestSuite 多个测试用例集合在一起,中文翻译过来叫测试套件,其实就是测试集。
TestLoader是用来加载TestCase到TestSuite中的(更通俗一点,就是用来把符合我们定义的条件的测试用例组合起来,成为一个测试集),一般会以参数的形式传进去一些条件,比如收集某个目录下所有的test case组成新的测试集。
TestRunner是来执行测试用例的,测试的结果会保存到TestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息
一个简单的测试例子
>>> class MyTest(unittest.TestCase):
#Run before whole testcase set execution, decorator classmethod is essential
@classmethod
def setUpClass(self):
print("UnitTest Begin...")
#Run after whole testcase set execution, decorator classmethod is essential
@classmethod
def tearDownClass(self):
print("UnitTest End...")
#Run before each test case execution
def setUp(self):
print("Begin...")
#Run after each test case execution
def tearDown(self):
print("End...")
def test_1(self):
self.assertEqual(1,1)
def test_2(self):
self.assertEqual(1,2) >>> if __name__ == '__main__':unittest.main() UnitTest Begin...
Begin...
End...
.Begin...
End...
FUnitTest End... ======================================================================
FAIL: test_2 (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<pyshell#41>", line 15, in test_2
AssertionError: 1 != 2 ----------------------------------------------------------------------
Ran 2 tests in 0.097s FAILED (failures=1)
在这个例子中,有几个函数要注意:
setUp()和tearDown():每个test case执行之前和执行之后要运行的操作:我们可以在这里定义测试的准备工作,比如链接数据库,web登录等等。
用装饰器classmethod装饰的setUpClass()和tearDownClass(): 跑类中定义的所有test cases之前和之后,需要执行的操作。
test_1()和test_2(),具体的测试用例,一定要以test为开头,因为unittest框架中,定义为,如果TestCase类中以test为开头的函数,将会作为具体的testcase收录进要执行的测试集里。
self.assertEqual(),是TestCase类中的断言函数,用来做判断的,用以判断该条测试用例是否通过。通过名字我们可以看出,这个函数的意思是判断两个值是否相等,如果相等,则用例通过,如果不等,则用例不通过。类似的,断言函数还有很多:有一个msg参数,如果指定msg参数的值,则将该信息作为失败的错误信息返回
三种常见测试写法
第一种: 搜索该模块下所有以test开头的测试用例方法,并自动执行它们
#执行测试用例方案一如下:
#unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行它们。 import unittest #定义测试类,父类为unittest.TestCase。
#可继承unittest.TestCase的方法,如setUp和tearDown方法,不过此方法可以在子类重写,覆盖父类方法。
#可继承unittest.TestCase的各种断言方法。
class Test(unittest.TestCase): def setUp(self):
self.number=raw_input('Enter a number:')
self.number=int(self.number) #定义测试用例,以“test_”开头命名的方法
#可使用unittest.TestCase类下面的各种断言方法用于对测试结果的判断
def test_case1(self):
print self.number
self.assertEqual(self.number,10,msg='Your input is not 10') def test_case2(self):
print self.number
self.assertEqual(self.number,20,msg='Your input is not 20') @unittest.skip('暂时跳过用例3的测试')
def test_case3(self):
print self.number
self.assertEqual(self.number,30,msg='Your input is not 30') def tearDown(self):
print 'Test over' #如果直接运行该文件(__name__值为__main__),则执行以下语句,常用于测试脚本是否能够正常运行
if __name__=='__main__':
#执行顺序是命名顺序:先执行test_case1,再执行test_case2
unittest.main()
第二种: 构造测试集,实例化test suite(即TestRunner类), 运行test suite中所有的测试用例。
'''
执行测试用例方案二如下:
先构造测试集
实例化测试套件
'''
suite=unittest.TestSuite()
#将测试用例加载到测试套件中。
#执行顺序是安装加载顺序:先执行test_case2,再执行test_case1
suite.addTest(Test('test_case2'))
suite.addTest(Test('test_case1'))
#执行测试用例
#实例化TextTestRunner类
runner=unittest.TextTestRunner()
#使用run()方法运行测试套件(即运行测试套件中的所有用例)
runner.run(suite)
第三种:通过收集指定目录下的目标测试用例,构造测试集再执行
#构造测试集(简化了方案二中先要创建测试套件然后再依次加载测试用例)
#执行顺序同方案一:执行顺序是命名顺序:先执行test_case1,再执行test_case2
test_dir = './'
discover = unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
#执行测试用例
#实例化TextTestRunner类
runner=unittest.TextTestRunner()
#使用run()方法运行测试套件(即运行测试套件中的所有用例)
runner.run(discover)
如何生成HTML和XML格式的测试报告
上面我们得到的测试结果是文本格式的,可读性不好,并且也无法直接用来作后续的测试结果数据处理,比如测试结果的分类统计等等。
那么有两种方式可供我们选择:HTML和XML
HTML格式的报告,就是网页格式,可读性会比较好。XML格式的报告,则比较方便作后续的数据处理。
需要注意的是,我们需要安装额外的package,即HtmlTestRunner和xmlrunner。
在配置好Pip的前提下,可以通过以下命令安装:
pip install html-testrunner pip instll xmlrunner
如果没有配置好pip或者用pip安装失败,则需要用以下方式安装(xmlrunner同理):
#!/usr/bin/python3
# -*- coding: utf-8 -*- import unittest
import HtmlTestRunner class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(),'FOO')
def test_isupper(self):
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(),['hello','world'])
with self.assertRaises(TypeError):
s.split(2) if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
suite.addTest(TestStringMethods('test_split'))
runner = HtmlTestRunner.HTMLTestRunner(output='MyUnitTest')
runner.run(suite)
最终我们会得到一个可读性比较好的网页报告。
XML报告:
有时我们需要得到格式化数据的测试报告,此时XML格式就要比HTML格式好的多。
因为XML格式的test result容易被读取和数据处理。
示例代码如下:
#!/usr/bin/python3
# -*- coding: utf-8 -*- import unittest
import xmlrunner class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(),'FOO')
def test_isupper(self):
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(),['hello','world'])
with self.assertRaises(TypeError):
s.split(2) if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
suite.addTest(TestStringMethods('test_split'))
#fp = open('result.html','w')
runner = xmlrunner.XMLTestRunner(output='MyUnitTest')
#runner = HtmlTestRunner.HTMLTestRunner(stream=fp,output='MyUnitTest')
runner.run(suite)
得到的结果是这样的:
<?xml version="1.0"?> -<testsuite time="0.000" tests="3" name="TestStringMethods-20181115000346" failures="0" errors="0"> <testcase time="0.000" name="test_upper" classname="TestStringMethods"/> <testcase time="0.000" name="test_isupper" classname="TestStringMethods"/> <testcase time="0.000" name="test_split" classname="TestStringMethods"/> -<system-out> <![CDATA[]]> </system-out> -<system-err> <![CDATA[]]> </system-err> </testsuite>
几个利用unittest做测试的实际例子
百度搜索测试用例
from selenium import webdriver
import unittest, time class BaiduTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30) #隐性等待时间为30秒
self.base_url = "https://www.baidu.com" def test_baidu(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys("unittest")
driver.find_element_by_id("su").click()
time.sleep(3)
title=driver.title
self.assertEqual(title, u"unittest_百度搜索") def tearDown(self):
self.driver.quit() if __name__ == "__main__":
unittest.main()
有道翻译测试用例
from selenium import webdriver
import unittest, time class YoudaoTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30) #隐性等待时间为30秒
self.base_url = "http://www.youdao.com" def test_youdao(self):
driver = self.driver
driver.get(self.base_url + "/")
driver.find_element_by_id("translateContent").clear()
driver.find_element_by_id("translateContent").send_keys(u"你好")
driver.find_element_by_id("translateContent").submit()
time.sleep(3)
page_source=driver.page_source
self.assertIn( "hello",page_source) def tearDown(self):
self.driver.quit() if __name__ == "__main__":
unittest.main()
web测试用例:通过测试套件TestSuite来组装多个测试用例。
import unittest
from test_case import test_baidu
from test_case import test_youdao #构造测试集
suite = unittest.TestSuite()
suite.addTest(test_baidu.BaiduTest('test_baidu'))
suite.addTest(test_youdao.YoudaoTest('test_youdao')) if __name__=='__main__':
#执行测试
runner = unittest.TextTestRunner()
runner.run(suite)
参考链接:
2. unittest
— Unit testing framework https://docs.python.org/3/library/unittest.html
Python中的单元测试模块Unittest快速入门的更多相关文章
- python中的单元测试模块unittest
unittest的属性: 该文以思维导图的形式描述unittest的重要属性. 其中前四个是unittest最核心的三个属性. testcase:测试用例: testsuite:测试套件,多个测试用例 ...
- Python中定时任务框架APScheduler的快速入门指南
前言 大家应该都知道在编程语言中,定时任务是常用的一种调度形式,在Python中也涌现了非常多的调度模块,本文将简要介绍APScheduler的基本使用方法. 一.APScheduler介绍 APSc ...
- [ Python入门教程 ] Python中日志记录模块logging使用实例
python中的logging模块用于记录日志.用户可以根据程序实现需要自定义日志输出位置.日志级别以及日志格式. 将日志内容输出到屏幕 一个最简单的logging模块使用样例,直接打印显示日志内容到 ...
- Python入门之Python中的logging模块
基本用法 下面的代码展示了logging最基本的用法. import logging import sys # 获取logger实例,如果参数为空则返回root logger logger = log ...
- python中的单元测试pyUnit
python中的单元测试pyUnit 在Python中进行单元测试时需要用到PyUnit模块,Python 2.1及其以后的版本都将PyUnit作为一个标准模块,但如果你使用的是较老版本的Pyth ...
- Python中的random模块,来自于Capricorn的实验室
Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...
- Python中的logging模块
http://python.jobbole.com/86887/ 最近修改了项目里的logging相关功能,用到了python标准库里的logging模块,在此做一些记录.主要是从官方文档和stack ...
- Python中的random模块
Python中的random模块用于生成随机数.下面介绍一下random模块中最常用的几个函数. random.random random.random()用于生成一个0到1的随机符点数: 0 < ...
- 浅析Python中的struct模块
最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的总结. 了解c语言 ...
随机推荐
- 前端JavaScript之DOM节点操作
1.HTML DOM是啥 Document Object Model:定义了访问和操作HTML文档的标准方法,把HTML文档呈现为带有元素,属性和文本的树状结构 2.解析过程 HTML加载完毕,渲染引 ...
- Hive[6] HiveQL 查询
6.1 SELECT ... FROM 语句 hive> SELECT name,salary FROM employees; --普通查询 hive>SELECT e.n ...
- 在windows7上配置xampp虚拟主机
在设置之前最好关闭xampp1.修改hosts文件进入C:\Windows\System32\drivers\etc目录,找到hosts文件.在# Localhost (DO NOT REMOVE) ...
- 【期望dp 质因数分解】cf1139D. Steps to One
有一种组合方向的考虑有没有dalao肯高抬啊? 题目大意 有一个初始为空的数组$a$,按照以下的流程进行操作: 在$1\cdots m$中等概率选出一个数$x$并添加到$a$的末尾 如果$a$中所有元 ...
- Delphi 编写DLL动态链接库文件的知识
一.DLL动态链接库文件的知识简介: Windows的发展要求允许同时运行的几个程序共享一组函数的单一拷贝.动态链接库就是在这种情况下出现的.动态链接库不用重复编译或链接,一旦装入内存,Dlls函数可 ...
- Spring Boot Shiro权限管理--自定义 FormAuthenticationFilter验证码整合
思路shiro使用FormAuthenticationFilter进行表单认证,验证校验的功能应该加在FormAuthenticationFilter中,在认证之前进行验证码校验. 需要写FormAu ...
- 路由器基础配置之单臂路由实现vlan间通信
我们将以上面的拓扑图开始进行配置,目的为设置单臂路由实现vlan间通信,设置4个vlan,pc0,1,2为vlan10 pc3,4,5为vlan20:pc6,7,8为vlan30:server0,1为 ...
- PHP.TP框架下商品项目的优化2-图片优化
图片存储.上传.显示优化 1.图片路径写进配置文件,当路径有变动时[因业务扩大,服务器存储图片空间不足等],只需修改配置文件,而不用修改代码 2.封装显示.上传.删除函数,实现代码重用 [可类比其他类 ...
- 多个".h"文件中声明及定义 全局变量和函数
一.".h"文件必须以如下格式书写 例:文件<CZ_efg_hi.h"> ------------文件内容----------- #ifndef CZ_Efg ...
- 1 Mongodb安装
1.NoSQL简介 NoSQL,全名Not Only SQL,指的是非关系型的数据库 随着访问量的上升,网站的数据库性能出现了问题,于是NoSQL被设计出来了 优点.缺点 优点 高扩展性 分布式计算 ...