Python中unittest单元测试框架的实例用法

  • 时间:
  • 6516人关注

这篇文章主要介绍了Python unittest单元测试框架的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,另外这篇文章主要知识点是关于Python、unittest、单元测试、的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子资料:

一、测试模型

下面这部分来自于某书籍资料,拿过来,按需参考一下:

测试模型

(1)线性测试

1、概念:

通过录制或编写对应应用程序的操作步骤产生的线性脚本。单纯的来模拟用户完整的操作场景。(操作,重复操作,数据)都混合在一起。

2、优点:每个脚本相对独立,且不产生其他依赖和调用。任何一个测试用例脚本拿出来都可以单独执行。

3、缺点:开发成本高,用例之间存在重复的操作。比如重复的用户登录和退出。

维护成本高,由于重复的操作,当重复的操作发生改变时,则需要逐一进行脚本的修改。

4.线性测试实例:用户登录

(2)模块化驱动测试

1、概念:

将重复的操作独立成功共模块,当用例执行过程中需要用到这一模块操作时则被调用。
操作+(重复操作,数据)混合在一起。例如,自动化测试的执行需要保持测试用例的独立性和完整性,所以每一条用例在执行时都需要登录和退出操作,so可以把登录和退出的操作封装为公共函数。

2、优点:由于最大限度消除了重复,从而提高了开发效率和提高测试用例的可维护性。

3、缺点:虽然模块化的步骤相同,但是测试数据不同。比如说重复的登录模块,如果登录用户不同,依旧要重复编写登录脚本。

4.实例:对公共模块,例如登陆和退出进行模块化封装

(3)数据驱动测试

1、概念:它将测试中的测试数据和操作分离,数据存放在另外一个文件中单独维护。

通过数据的改变从而驱动自动化测试的执行,最终引起测试结果的改变。

操作+重复操作+数据分开。

2、优点:

通过这种方式,将数据和重复操作分开,可以快速增加相似测试,完成不同数据情况下的测试。

3、实例从excel表格读取用户名密码,登录邮箱。

二、unittest框架

用Python搭建自动化测试框架,需要组织用例以及测试执行,大部分推荐的是unittest。现在用的也是这个,随着了解,也有其他的框架,有时间再多去学习,保持持续学习哦~

附上官方文档地址:链接描述https://docs.python.org/2.7/library/unittest.html#

unittest是Python自带的单元测试框,可以用来作自动化测试框架的用例组织执行框架。优点:提供用例组织与执行方法;提供比较方法;提供丰富的日志、清晰的报告。
大致流程:

  • 写好TestCase
  • 由TestLoader加载TestCase到TestSuite
  • 然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中。

通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run()来执行,或者可以直接通过TextTestRunner来执行用例。

在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果。

unittest中最核心的部分是:TestFixture、TestCase、TestSuite、TestRunner。

1、Test fixture

用于一个测试环境的准备和销毁还原。

当测试用例每次执行之前需要准备测试环境,每次测试完成后还原测试环境,比如执行前连接数据库、打开浏览器等,执行完成后需要还原数据库、关闭浏览器等操作。这时候就可以启用testfixture。

  • setUp():准备环境,执行每个测试用例的前置条件;
  • tearDown():环境还原,执行每个测试用例的后置条件;
  • setUpClass():必须使用@classmethod装饰器,所有case执行的前置条件,只运行一次;
  • tearDownClass():必须使用@classmethod装饰器,所有case运行完后只运行一次;

例如:

# 重写TestCase的setUp() tearDown()方法:在每个测试方法执行前以及执行后各执行一次
def setUp(self): # 钩子方法
 print("do something before test : prepare environment")
def tearDown(self): # 钩子方法
 print("do something after test : clean up ")

2、TestCase

类,unittest.TestCase

一个类class继承 unittest.TestCase,就是一个测试用例。一个TestCase的实例就是一个测试用例,就是一个完整的测试流程。

包括测试前环境准备setUp()|setUpClass()、执行代码run()、测试环境后的还原tearDown()|tearDownClass()。
继承自unittest.TestCase的类中,测试方法的名称要以test开头。且只会执行以test开头定义的方法(测试用例)。

例如:【先准备待测试的方法function.py】

#!/usr/bin/python3
# -*- coding:utf-8 -*-
def add(a,b):
 return a+b
def minus(a,b):
 return a-b
def multi(a,b):
 return a*b
def divide(a,b):
 return a/b

【测试脚本】:

import unittest
from A_UnitTest_basicDemo_ok.function import *

class TestFunc(unittest.TestCase):
 # 继承自unittest.TestCase
 # 重写TestCase的setUp()、tearDown()方法:在每个测试方法执行前以及执行后各执行一次
 def setUp(self):
  print("do something before test : prepare environment")

 def tearDown(self):
  print("do something after test : clean up ")
 
 # 测试方法均已test开头,否则是不被unittest识别的
 def test_add(self):
  print("add:")
  self.assertEqual(3,add(1,2))

 def test_minus(self):
  print("minus")
  self.assertEqual(3,minus(5,2))

 def test_multi(self):
  print("multi")
  self.assertEqual(6,multi(2 ,3))

 def test_divide(self):
  print("divide")
  self.assertEqual(2,divide(4,2))

if __name__ == "__main__":
 # 在main()中加verbosity参数,可以控制输出的错误报告的详细程度
 # verbosity=*:默认是1;设为0,则不输出每一个用例的执行结果;2-输出详细的执行结果
 unittest.main(verbosity=2)

或者也可以使用setUpClass() & tearDownClass()方法:

# 如果想在所有case执行之前准备一次测试环境,并在所有case执行结束后再清理环境
@classmethod
def setUpClass(cls):
 print("this setupclass() method only called once")
@classmethod
def tearDownClass(cls):
 print("this teardownclass() method only called once too")

【verbosity】

在测试用例文件的末尾加上如下代码:

if __name__ == "__main__":
 unittest.main(verbosity=2) # 输出详细的错误报告

在unittest.main()中加参数verbosity可以控制错误报告的详细程度:默认为1。0,表示不输出每一个用例的执行结果;2表示详细的执行报告结果。

【执行结果】:输出到控制台

this setupclass() method only called once
test_add (__main__.TestFunc) ... ok
add:
test_divide (__main__.TestFunc) ... ok
divide
test_minus (__main__.TestFunc) ... ok
minus
test_multi (__main__.TestFunc) ... ok
multi

this teardownclass() method only called once too
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

3、TestSuite

上述简单的测试会产生两个问题,可不可以控制test测试用例的执行顺序?若不想执行某个测试用例,有没有办法可以跳过?
对于执行顺序,默认按照test的 A-Z、a-z的方法执行。若要按自己编写的用例的先后关系执行,需要用到testSuite。
把多个测试用例集合起来,一起执行,就是testSuite。testsuite还可以包含testsuite。

一般通过addTest()或者addTests()向suite中添加。case的执行顺序与添加到Suite中的顺序是一致的。

例如:run_main.py

if __name__ == "__main__":
 suite = unittest.TestSuite()
# 定义list,按照list里的顺序执行测试用例
tests=[TestFunc("test_add"),TestFunc("test_minus"),TestFunc("test_multi"),TestFunc("test_divide")]
suite.addTests(tests)
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

TestSuite可以再包含testsuite,示例如下:

suite1 = module.TheTestSuite()
suite2=module.TheTestSuite()
alltests=unittest.TestSuite([suite1],[suite2])

跳过某个case:skip装饰器

若想让某个测试用例不执行,有没有办法呢?当然是有的,可以使用skip装饰器。

例如:

@unittest.skip("i don't want to run this case -> test_minus() ... ")
def test_minus(self):
 print("minus")
 self.assertEqual(3,minus(5,2))

加上“@unittest.skip()”后,执行看看,对比控制台的输出结果就可以明显看出区别了。

Skip装饰器有如下几种情况:

(1)skip():无条件跳过

@unittest.skip("i don't want to run this case. ")

(2)skipIf(condition,reason):如果condition为true,则 skip

@unittest.skipIf(condition,reason)

(3)skipUnless(condition,reason):如果condition为False,则skip

@unittest.skipUnless(condition,reason)

(4)还可以使用TestCase.skipTest(reason)。例如:

def test_divide(self):
 self.skipTest('do not run test_divide()')
 print("divide")
 self.assertEqual(2,divide(4,2))

控制台输出(部分):test_divide (__main__.TestFunc) ... skipped 'do not run test_divide()'

4、TestLoader

TestLoadder用来加载TestCase到TestSuite中。

loadTestsFrom*()方法从各个地方寻找testcase,创建实例,然后addTestSuite,再返回一个TestSuite实例。

该类提供以下方法:

unittest.TestLoader().loadTestsFromTestCase(testCaseClass)
unittest.TestLoader().loadTestsFromModule(module)
unittest.TestLoader().loadTestsFromName(name,module=None)
unittest.TestLoader().loadTestsFromNames(names,module=None)
unittest.TestLoader().getTestCaseNames(testCaseclass)
unittest.TestLoader().discover()

TestLoader 之discover:

用discover()来加载测试多个测试用例,再用TextRunner类的run()方法去一次执行多个脚本的用例,达到批量执行的效果。

discover方法里面有三个参数:

  • -case_dir:这个是待执行用例的目录。
  • -pattern:这个是匹配脚本名称的规则,test*.py意思是匹配test开头的所有脚本。
  • -top_level_dir:这个是顶层目录的名称,一般默认等于None就行了。

TextTestRunner():执行测试用例。runner.run(test)会执行TestSuite、TestCase中的run(result)方法。

如下:run_main.py示例

import unittest
import os
# 用例的路径
case_path = os.path.join(os.getcwd(),"case")
# 报告存放的路径
report_path = os.path.join(os.getcwd(),"report")
def all_cases():
 discover= unittest.defaultTestLoader.discover(case_path,pattern="test*.py",top_level_dir=None)
 print(discover)
 return discover
if __name__ == "__main__":
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(all_cases())

5、生成测试报告

生成TXT测试报告

代码示例:

if __name__ == "__main__":
 suite = unittest.TestSuite()
 # 生成.txt的测试报告(控制台的输出写入到文件中)
 suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFunc))
 with open('UnittestTextReport.txt','a') as f:
  runner = unittest.TextTestRunner(stream=f,verbosity=2)
  runner.run(suite)

可以看到在目录下,生成了UnittestTextReport.txt文件。

但是txt格式的文件太过于简陋。我们可以借助与第三方提供的库来输出更加形象的html报告,也可以自定义输出自己想要格式的html格式的报告。

  1. 生成HTML测试报告
  2. 先下载HTMLTestRunner.py(注意Python的版本),http://tungwaiyip.info/software/HTMLTestRunner.html。然后放在Python的Lib目录下;
  3. 在run_main.py文件中加入:from HTMLTestRunner import HTMLTestRunner

HTMLTestRunner()方法有三个参数:

  • --stream:测试报告写入文件的存储区域
  • --title:测试报告的主题
  • --description:测试报告的描述

代码示例:

if __name__ == "__main__":
 suite = unittest.TestSuite()
 # 生成HTML格式的具体测试报告
 with open('HtmlReport.html','wb') as f: # 在python3,要写成'wb' or 'wr'
  runner = HTMLTestRunner(stream=f,title='function test 
report',description='generated by HTMLTestRunner',verbosity=2)
  runner.run(suite)

三、代码示例

function.py

#!/usr/bin/python3
# -*- coding:utf-8 -*-
def add(a,b):
 return a+b
def minus(a,b):
 return a-b
def multi(a,b):
 return a*b
def divide(a,b):
 return a/b

Test_function.py

#!/usr/bin/python3
# -*- coding:utf-8 -*-
import unittest
from UnitTest_1.function import * # from..import ... :要指定文件的路径

class TestFunc(unittest.TestCase): # unittest.TestCase
# 如果想在所有case执行之前准备一次测试环境,并在所有case执行结束后再清理环境
 @classmethod
 def setUpClass(cls):
  print("this setupclass() method only called once")
 @classmethod
 def tearDownClass(cls):
  print("this teardownclass() method only called once too")

 # 测试方法均已test开头,否则是不被unittest识别的
 def test_add(self):
  print("add:")
  self.assertEqual(3,add(1,2))
 def test_minus(self):
  print("minus")
  self.assertEqual(3,minus(5,2))
 # 如果想临时跳过某个case:skip装饰器
 @unittest.skip("i don't want to run this case. ")
 def test_multi(self):
  print("multi")
  self.assertEqual(6,multi(2,3))
 def test_divide(self):
  print("divide")
  self.assertEqual(2,divide(5,2))

if __name__ == "__main__":
 # 在main()中加verbosity参数,可以控制输出的错误报告的详细程度
 # verbosity=*:默认是1;设为0,则不输出每一个用例的执行结果;2-输出详细的执行结果
 unittest.main(verbosity=2)

Test_suite.py

#!/usr/bin/python3
# -*- coding:utf-8 -*-

import unittest
from UnitTest_1.test_function import TestFunc
from HTMLTestRunner import HTMLTestRunner
# 在Python3中已经没有 StringIO,所以引用的时候要注意
from io import StringIO

if __name__ == "__main__":
 suite = unittest.TestSuite()
 # 定义list,按照list里的顺序执行测试用例
 tests = [TestFunc("test_add"),TestFunc("test_minus"),TestFunc("test_multi"),TestFunc("test_divide")]
 suite.addTests(tests)
 '''
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)
 '''
 
 # 生成.txt的测试报告(控制台的输出写入到文件中)
 '''
 suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFunc))
 with open('UnittestTextReport.txt','a') as f:
  runner = unittest.TextTestRunner(stream=f,verbosity=2)
  runner.run(suite)
 '''

 # 生成HTML格式的具体测试报告
 with open('HtmlReport.html','wb') as f: # 在python3,要写成'wb' or 'wr'
  runner = HTMLTestRunner(stream=f,title='function test report',description='generated by 
     HTMLTestRunner',verbosity=2)
  runner.run(suite)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。


上一篇:Python中模块导入时全局变量__all__的作用

下一篇:Python openpyxl遍历所有sheet查找特定字符串的实例方法

相关内容

  • Python如何限制输出日志的大小

    这篇文章主要介绍了Python 限制输出日志的大小方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

    05-06Python限制日志大小

    阅读更多
  • python实现可视化的MD5、sha256哈希加密小工具

    这篇文章主要介绍了详解python实现可视化的MD5、sha256哈希加密小工具,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    04-07python MD5、sha256哈希加密

    阅读更多
  • Python gevent协程切换实现方法

    这篇文章主要介绍了Python gevent协程切换实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    04-07Python gevent协程切换

    阅读更多
  • python/golang实现循环链表的代码

    这篇文章主要介绍了python/golang如何实现循环链表,帮助大家更好的理解和学习循环链表的实现方法,感兴趣的朋友可以了解下

    04-07python/golang 循环链表

    阅读更多
  • 2020版Python学习路线图(附学习资料)

    这篇文章主要介绍了Python学习路线图(2020最新版),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    04-07Python学习路线图

    阅读更多
  • Python程序设计开发宝典

    Python程序设计开发宝典

    本书深入剖析Python 3.5.x、Python 3.6.x及更新版本的内置对象和标准库对象高级用法,150个案例源代码和超过1000个演示性代码片段,可以作为Python程序设计教材

    大小:42.8 MBPython

    点击下载
  • Web接口开发与自动化测试:基于Python语言

    Web接口开发与自动化测试:基于Python语言

    Web接口开发与自动化测试:基于Python语言 以接口测试为主线,以Web开发为切入点,全面介绍了Web接口开发与自动化测试过程中使用的相关技术。 全书分为15章,第1章介绍了Python的基础知识,解

    大小:39.9 MBWeb接口

    点击下载
  • Python 3.7编程快速入门

    Python 3.7编程快速入门

    Python以其具备丰富多彩和强劲的库,及其简易非常容易入门的特点,现阶段活跃性在诸多技术性行业,包含人工智能技术、数据分析解决、深度学习与深度神经网络、金融业量化投资、网络开

    大小:18.5 MBPython 3.7

    点击下载
  • Python3程序开发指南

    Python3程序开发指南

    本书全面深入地讲解了Python语言,讲述了构成Python语言的8个关键要素,包含数据类型、控制结构与函数、模块、正则表达式、GUI程序设计等各个方面

    大小:419.2 MBPython

    点击下载
  • Python网络爬虫实战

    Python网络爬虫实战

    本书从Python的安装开始,详细讲解了Python从简单程序延伸到Python网络爬虫的全过程。本书从实战出发,根据不同的需求选取不同的爬虫,有针对性地讲解了几种Python网络爬虫。本书共8章,涵盖

    大小:47.4 MBPython爬虫

    点击下载
  • Python3标准库

    Python3标准库

    这书由杰出Python权威专家亲身绘制,Python語言的关键开发者鼎力推荐。 对程序猿来讲,标准库与語言自身 一样关键,它就象1个百宝箱,能为各种各样普遍的每日任务出示极致的解决方法,因

    大小:148.9 MBPython

    点击下载
  • Python游戏编程快速上手(第4版)

    Python游戏编程快速上手(第4版)

    本书通过小巧有趣的游戏来教授Python编程,采用直接展示游戏的源代码并通过实例来解释编程的原理的方式,帮助读者掌握Python游戏编程的基本技能,适合不同年龄和层次的Python编程初学者阅读

    大小:41.2 MBPython

    点击下载

学习笔记

44小时50分钟前回答

总结python bottle框架支持jquery ajax的RESTful风格的PUT和DELETE方法

这两天在用python的bottle框架开发后台管理系统,接口约定使用RESTful风格请求,前端使用jquery ajax与接口进行交互,使用POST与GET请求时都正常,而Request Method使用PUT或DELETE请求时,直接爆HTTP Error 405: Method Not Allowed错误。而ajax提交的Request Method值DELETE也变成了OPTIONS了。 度娘了好多答案,要么说是浏览器不支持,要么说自己重新封装jquery,还有其他的一些方法......呃...重新封装jquery就算了,javascript不是很熟无从下手,然后其他方法一个个都试过也没有用,想来想去还是从python源码入手好一点。 说干就干,在主文件main.py中,添加了bottle勾子 @hook(before_request) 函数(引用:from bottle import request),然后添加r……

32小时21分钟前回答

浅析python消息队列框架

python消息队列框架有哪些?下面给大家介绍几款好用的消息队列框架: RabbitMQ 是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。同时实现了一个经纪人(Broker)构架,这意味着消息在发送给客户端时先在中心队列排队。对路由(Routing),负载均衡(Load balance)或者数据持久化都有很好的支持。 Redis 是一个Key-Value的NoSQL数据库,开发维护很活跃,虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次……

34小时33分钟前回答

python框架知识点汇总

从GitHub中整理出的15个最受欢迎的Python开源框架。这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等。 Django: Python Web应用开发框架 Django 应该是最出名的Python框架,GAE甚至Erlang都有框架受它影响。Django是走大而全的方向,它最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。 Diesel:基于Greenlet的事件I/O框架 Diesel提供一个整洁的API来编写网络客户端和服务器。支持TCP和UDP。 Flask:一个用Python编写的轻量级Web应用框架 Flask是一个使用Python编写的轻量级Web应用框架。基于Werkzeug WSGI工具箱和Jinja2 模板引擎。Flask也被……

38小时57分钟前回答

机器学习的框架推荐Python的原因

13个机器学习的框架偏向于Python的原因,供大家参考,具体内容如下 前言 主要有以下原因: 1. Python是解释语言,程序写起来非常方便 写程序方便对做机器学习的人很重要。 因为经常需要对模型进行各种各样的修改,这在编译语言里很可能是牵一发而动全身的事情,Python里通常可以用很少的时间实现。 举例来说,在C等编译语言里写一个矩阵乘法,需要自己分配操作数(矩阵)的内存、分配结果的内存、手动对BLAS接口调用gemm、最后如果没用smart pointer还得手动回收内存空间。Python几乎就是import numpy; numpy.dot两句话的事。 当然现在很多面向C/C++库已经支持托管的内存管理了,这也让开发过程容易了很多,但……