python自动化测试三部曲之unittest框架的实现


Posted in Python onOctober 07, 2020

终于等到十一,有时间写博客了,准备利用十一这几天的假期把这个系列的博客写完

该系列文章本人准备写三篇博客

第一篇:介绍python自动化测试框架unittest

第二篇:介绍django框架+request库实现接口测试

第三篇:介绍利用Jenkins实现持续集成

今天进入第一篇,unittest框架介绍

一、unittest简述

unittest是python语言的单元测试框架,在python的官方文档中,对unittest单元测试框架进行了详细的介绍,感兴趣的读者可以到https://www.python.org/doc

网站去了解;本篇博客重点介绍unittest单元测试框架在自动化测试中的应用

unittest单元测试框架提供了创建测试用例,测试套件,和批量执行测试用例的方法,在python安装成功后,unittest单元测试框架可以直接导入使用,他属于python的标准库;作为单元测试的框架,unittest单元测试框架也是对程序的最小模块进行的一种敏捷化的测试。在自动化测试i中,我们虽然不需要做白盒测试,但是必须知道所使用语言的单元测试框架,这是因为后面我们测试,就会遇到用例组织的问题,虽然函数式编程和面向对象编程提供了对代码的重构,但是对于所编写的每个测试用例,不可能编写成一个函数来调用执行;利用单元测试框架,可以创建一个类,该类继承unittest的TestCase,这样可以把每个TestCase看成是一个最小的单元,由测试套件组织起来,运行时直接执行即可,同时可引入测试报告。unittest各个组件的关系如果

TestCase------------------------------->TestFixture(测试固件)
|
|
|
TestSuite(测试套件)----------------------->TestRunner(测试执行)-------------------->TestReport(测试报告)

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

二、测试固件(TestFixture)

在unittest单元测试框架中,测试固件用于处理初始化的操作,例如,在对百度的搜索进行测试前,首先需要打开浏览器并且进入百度的首页;测试结束后,需要关闭浏览器;测试固件提哦功能了两种执行形式,一种是每执行一个测试用例,测试固件就会被执行一次;另外一种就不管有多少个用例i,测试固件只会执行一次

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

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

1、测试固件每次均执行

unittest单元测试框架提供了名为setUp的tearDown的测试固件。下面,我们通过编写一个例子来看测试固件的执行方式,测试代码如下

import unittest

class Test1(unittest.TestCase):

 # 测试固件之前置条件
 def setUp(self):
  print("这是前置条件")

 # 测试固件之后置条件
 def tearDown(self):
  print("这是后置条件")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)

执行结果如下

python自动化测试三部曲之unittest框架的实现

他的执行顺序是先执行setUp方法,在执行具体的用例,最后执行tearDown方法

2、测试固件只执行一次

钩子方法setUp和tearDown虽然经常使用,但是在自动化测试中,一个系统的测试用例多达上千条,每次都执行一次的setUp和tearDown方法会耗费大量的性能,在unittest单元测试框架中还可以使用另外一种测试固件来解决这一问题,他就是setUpClass和tearDownClass方法,该测试固件方法是类方法,需要在方法上面加装饰器@classmethod,使用该测试固件,不管有多少个用例,测试固件只执行一次,具体代码如下

import unittest

class Test1(unittest.TestCase):
 # def setUp(self):
 #  print("这是前置条件")
 #
 # def tearDown(self):
 #  print("这是后置条件")

 @classmethod
 def setUpClass(cls):
  print("这是类方法前置条件")

 @classmethod
 def tearDownClass(cls):
  print("这是类方法后置条件")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)

结果如下

python自动化测试三部曲之unittest框架的实现

3、两种测试固件并存

import unittest


class Test1(unittest.TestCase):
 def setUp(self):
  print("这是前置条件")

 def tearDown(self):
  print("这是后置条件")

 @classmethod
 def setUpClass(cls):
  print("这是类方法前置条件")

 @classmethod
 def tearDownClass(cls):
  print("这是类方法后置条件")

 def test_case1(self):
  print("test_case1")

 def test_case2(self):
  print("test_case2")


if __name__ == '__main__':
 unittest.main(verbosity=2)

执行结果如下

python自动化测试三部曲之unittest框架的实现

结果表明,先执行被@classmethod装饰器装饰的测试固件,在执行普通的测试固件

三、测试执行

在以上事例中,可以看到测试用例的执行是在主函数中,unittest调用的是main,代码如下,TestProjram还是一个类,再来看该类的构造函数,代码如下

main = TestProgram

TestProjram还是一个类,再来看该类的构造函数,代码如下

class TestProgram(object):
 """A command-line program that runs a set of tests; this is primarily
  for making test modules conveniently executable.
 """
 # defaults for testing
 module=None
 verbosity = 1
 failfast = catchbreak = buffer = progName = warnings = None
 _discovery_parser = None

 def __init__(self, module='__main__', defaultTest=None, argv=None,
     testRunner=None, testLoader=loader.defaultTestLoader,
     exit=True, verbosity=1, failfast=None, catchbreak=None,
     buffer=None, warnings=None, *, tb_locals=False):
  if isinstance(module, str):
   self.module = __import__(module)
   for part in module.split('.')[1:]:
    self.module = getattr(self.module, part)
  else:
   self.module = module
  if argv is None:
   argv = sys.argv

  self.exit = exit
  self.failfast = failfast
  self.catchbreak = catchbreak
  self.verbosity = verbosity
  self.buffer = buffer
  self.tb_locals = tb_locals
  if warnings is None and not sys.warnoptions:
   # even if DeprecationWarnings are ignored by default
   # print them anyway unless other warnings settings are
   # specified by the warnings arg or the -W python flag
   self.warnings = 'default'
  else:
   # here self.warnings is set either to the value passed
   # to the warnings args or to None.
   # If the user didn't pass a value self.warnings will
   # be None. This means that the behavior is unchanged
   # and depends on the values passed to -W.
   self.warnings = warnings
  self.defaultTest = defaultTest
  self.testRunner = testRunner
  self.testLoader = testLoader
  self.progName = os.path.basename(argv[0])
  self.parseArgs(argv)
  self.runTests()

在unittest模块中包含的main方法,可以方便的将测试模块转变为可以运行的测试脚本。main使用unittest.TestLoader类来自动查找和加载模块内的测试用例,TestProgram类中的该部分的代码如下

def createTests(self):
  if self.testNames is None:
   self.test = self.testLoader.loadTestsFromModule(self.module)
  else:
   self.test = self.testLoader.loadTestsFromNames(self.testNames,
               self.module)

在执行测试用例时候,在main方法中加入了verbosity=2,代码如下

if __name__ == '__main__':
 unittest.main(verbosity=2)

下面解释一下verbosity部分,在verbosity中默认是1。0代表执行的测试总数和全局结果,2代表详细的信息

四、测试套件,TestSuite

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

1、直接执行案例

我们在func.py这个文件中定义加减乘除4个测试函数

#Auther Bob
#--*--conding: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

python自动化测试三部曲之unittest框架的实现

然后在myunittest.py文件中定义我们的测试代码,这里用到了断言,我们后面会介绍

from test1 import func

class Test2(unittest.TestCase):
 def setUp(self):
  print("前置条件")

 def tearDown(self):
  print("后置条件")

 def test_add(self):
  self.assertEqual(3,func.add(1,2))

 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))

 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))

 def test_divide(self):
  self.assertEqual(10,func.divide(100,10))


if __name__ == '__main__':
 unittest.main(verbosity=2)

执行结果如下

python自动化测试三部曲之unittest框架的实现

2、添加案例到测试套件中

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

如果用到测试套件TestSuite,则需要先写好测试代码,但是先不要执行

我们同样在myunittest.py文件中定义我们的测试代码

from test1 import func


class Test3(unittest.TestCase):
 def setUp(self):
  print("前置条件")

 def tearDown(self):
  print("后置条件")


 def test_add(self):
  self.assertEqual(3,func.add(1,2))


 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))


 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))

 def test_divide(self):
  self.assertEqual(10,func.divide(100,10))

我们在test_suit.py文件中引入测试案例,然后通过TestSuite类的addTests方法把测试用例添加到测试套件中

import unittest
from test1.myunittest import Test3
# from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 # 输出信息到控制台
 
 # 实例化一个TestSuite类
 suite = unittest.TestSuite()
 
 # 把需要执行的案例放在一个list中
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]
 
 # 把案例添加到实例化好的测试套件中
 suite.addTests(tests)
 # t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 # suite.addTests(tests)
 
 # 实例化一个参数执行类
 runner = unittest.TextTestRunner(verbosity=2)
 
 # 测试执行类的实例执行测试套件
 runner.run(suite)

以上的案例我们是添加一个文件的测试案例,我们同样可以添加多个文件中的案例到一个测试套件中,然后执行这个测试套件即可

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 # 输出信息到控制台

 # 实例化一个TestSuite类
 suite = unittest.TestSuite()

 # 把需要执行的案例放在一个list中
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]

 # 把案例添加到实例化好的测试套件中
 suite.addTests(tests)
 
 # 添加另外一个文件中的测试案例到测试套件中
 t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 suite.addTests(t)

 # 实例化一个参数执行类
 runner = unittest.TextTestRunner(verbosity=2)

 # 测试执行类的实例执行测试套件
 runner.run(suite)

上面的执行方式是输出结果到控制台,我们也可以输出结果到文件中

import unittest
from test1.myunittest import Test3
from test1.myunittest2 import Test3 as t3



if __name__ == '__main__':
 
 # 输出信息到txt文件中
 suite = unittest.TestSuite()
 tests = [Test3("test_add"), Test3("test_minus"), Test3("test_multi"), Test3("test_divide")]
 suite.addTests(tests)
 t = [t3("test_add"), t3("test_minus"), t3("test_multi"), t3("test_divide")]
 suite.addTests(t)
 with open('UnittestTextReport.txt', 'a') as f:
  runner = unittest.TextTestRunner(stream=f, verbosity=2)
  runner.run(suite)

3、直接添加测试类到测试套件中

案例一个一个添加还是比较麻烦,我们可以直接添加一个测试类到测试套件中

利用下面的方法加载一个测试类

unittest.TestLoader().loadTestsFromTestCase(t3)
import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromTestCase(t3)
 # 参数是一个类,而这个类必须是unittest.TestCase的子类或者孙类
 suite.addTests(test_cases1)
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)

4、直接加载一个模块到测试套件中,如果这个模块中有多个类,则会把所有的类的测试案例加载到测试套件中

unittest.TestLoader().loadTestsFromModule(myunittest)
import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':
 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromModule(myunittest)
 # 参数是一个模块,会把这个模块里的所有case加载进来
 suite.addTests(test_cases1)
 runner = unittest.TextTestRunner(verbosity=2)
 runner.run(suite)

我给大家截图看下

python自动化测试三部曲之unittest框架的实现

5、通过案例名称添加案例到测试套件中

test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')
import unittest
from unittest import TestLoader

from test1 import myunittest

from test1.myunittest2 import Test3 as t3

if __name__ == '__main__':

 suite = unittest.TestSuite()
 loader = TestLoader()
 test_cases1 = unittest.TestLoader().loadTestsFromName('test1.myunittest2.Test3.test_minus')
 # 加载某个cese
 runner = unittest.TextTestRunner(verbosity=2)
 suite.addTests(test_cases1)
 runner.run(suite)

我截图给大家看下目录结构

python自动化测试三部曲之unittest框架的实现

五、忽略执行案例

在实际的项目中,有些案例我们可能暂时不需要执行,如果有这样的问题,我们该怎么办,unittest框架已经为我们提供了解决方案

1、无条件跳过该案例,用该装饰器修饰要执行的案例,则该案例会被忽略不执行

@unittest.skip("do not exec")
@unittest.skip("do not exec")
 # 无条件跳过执行该案例
 def test_add(self):
  self.assertEqual(3,func.add(1,2))

2、满足某个条件才跳过该案例

@unittest.skipIf(4 > 3,"2 > 3 do not exec")
@unittest.skipIf(4 > 3,"2 > 3 do not exec")
 # 满足某个条件才跳过执行
 def test_minus(self):
  self.assertEqual(4,func.minus(5,1))

3、不满足某个条件才跳过案例

@unittest.skipUnless(4 < 3,"hahah")
@unittest.skipUnless(4 < 3,"hahah")
 # 不满足某个条件才跳过执行
 def test_multi(self):
  self.assertEqual(4,func.multi(2,2))

4、我们也可以在案例里面定义忽略执行这条案例

def test_divide(self):
  self.skipTest("wydd")
  self.assertEqual(10,func.divide(100,10))

六、断言

断言就是判断实际测试结果与预期结果是否一致,一致则测试通过,否则失败。因此,在自动化测试中,无断言的测试用例是无效的,这是因为当一个功能自动化已经全部实现,在每次版本迭代中执行测试用例时,执行的结果必须是权威的,也就是说自动化测试用例执行结果应该无功能性或者逻辑性问题,在自动化测试中最忌讳的就是自动化测试的用例虽然是通过的,但是被测试的功能却是存在问题的,自动化测试用例经常应用在回归测试中,发现的问题不是特别多,如果测试结果存在功能上的问题,则投入了人力去做的自动化参数就没有多大的意义了,所以每一个测试用例必须要有断言;在测试的结果中只有两种可能,一种是执行通过,另外一种是执行失败,也就是功能存在问题,在TestCase类中提供了assert方法来检查和报告失败,常用的方法如下

self.assertEqual(3,func.add(1,2))
  # 判断是否相等
  
  self.assertNotEqual()
  # 判断是否不等于
  
  self.assertTrue()
  # 判断布尔值是否为True
  
  self.assertFalse()
  # 判断布尔值是否为False
  
  self.assertIs()
  # 判断类型是否相同
  
  self.assertIsNot()
  # 判断类型是否不同
  
  self.assertIsNone()
  # 判断是否为None
  
  self.assertIsNotNone()
  # 判断是否不为None
  
  self.assertIn()
  # 判断在某个范围内
  
  self.assertNotIn()
  # 判断是否不在某个范围内
  
  self.assertIsInstance()
  # 判断是否为某个类的实例
  
  self.assertNotIsInstance()

到此这篇关于python自动化测试三部曲之unittest框架的实现的文章就介绍到这了,更多相关python unittest框架内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python实现计算资源图标crc值的方法
Oct 05 Python
Python选择排序、冒泡排序、合并排序代码实例
Apr 10 Python
深入解析Python中函数的参数与作用域
Mar 20 Python
Windows平台Python连接sqlite3数据库的方法分析
Jul 12 Python
python爬虫获取多页天涯帖子
Feb 23 Python
朴素贝叶斯分类算法原理与Python实现与使用方法案例
Jun 26 Python
Flask框架实现给视图函数增加装饰器操作示例
Jul 16 Python
python基于plotly实现画饼状图代码实例
Dec 16 Python
python求一个字符串的所有排列的实现方法
Feb 04 Python
Python3使用腾讯云文字识别(腾讯OCR)提取图片中的文字内容实例详解
Feb 18 Python
Pycharm自动添加文件头注释和函数注释参数的方法
Oct 23 Python
python3定位并识别图片验证码实现自动登录功能
Jan 29 Python
浅谈anaconda python 版本对应关系
Oct 07 #Python
简述python&amp;pytorch 随机种子的实现
Oct 07 #Python
详解基于python的全局与局部序列比对的实现(DNA)
Oct 07 #Python
python单元测试框架pytest的使用示例
Oct 07 #Python
利用python批量爬取百度任意类别的图片的实现方法
Oct 07 #Python
Python colormap库的安装和使用详情
Oct 06 #Python
Django-Scrapy生成后端json接口的方法示例
Oct 06 #Python
You might like
PHP4实际应用经验篇(3)
2006/10/09 PHP
php date与gmdate的获取日期的区别
2010/02/08 PHP
深入Apache与Nginx的优缺点比较详解
2013/06/17 PHP
PHP错误WARNING: SESSION_START() [FUNCTION.SESSION-START]解决方法
2014/05/04 PHP
Yii2简单实现多语言配置的方法
2016/07/23 PHP
PHP设计模式之装饰器模式定义与用法详解
2018/04/02 PHP
js实现权限树的更新权限时的全选全消功能
2009/02/17 Javascript
eval的两组性能测试数据
2012/08/17 Javascript
Three.js源码阅读笔记(基础的核心Core对象)
2012/12/27 Javascript
JavaScript判断变量是对象还是数组的方法
2014/08/28 Javascript
javascript实现左右控制无缝滚动
2014/12/31 Javascript
JavaScript模拟实现键盘打字效果
2015/06/29 Javascript
浅析JS中对函数function的理解(基础篇)
2016/10/14 Javascript
从0开始学Vue
2016/10/27 Javascript
详解前后端分离之VueJS前端
2017/05/24 Javascript
JavaScript对象_动力节点Java学院整理
2017/06/23 Javascript
vue.js全局API之nextTick全面解析
2017/07/07 Javascript
vue获取input输入值的问题解决办法
2017/10/17 Javascript
使用JavaScript破解web
2018/09/28 Javascript
在Vue中使用axios请求拦截的实现方法
2018/10/25 Javascript
vue实现简单的星级评分组件源码
2018/11/16 Javascript
继承行为在 ES5 与 ES6 中的区别详解
2019/12/24 Javascript
[56:24]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#1Liquid VS MVP.Phx第二局
2016/03/04 DOTA
[00:14]PWL:老朋友Mushi拍VLOG与中国玩家问好
2020/11/04 DOTA
python for循环remove同一个list过程解析
2019/08/14 Python
如何基于python把文字图片写入word文档
2020/07/31 Python
中国最大的潮流商品购物网站:YOHO!BUY有货
2017/01/07 全球购物
欧尚俄罗斯网上超市:Auchan俄罗斯
2018/05/03 全球购物
大学生求职简历的自我评价范文
2013/10/12 职场文书
《可爱的动物》教学反思
2014/02/22 职场文书
学生请假条格式
2014/04/11 职场文书
投资合作协议书范本
2014/04/17 职场文书
大学生考试作弊检讨书
2014/09/21 职场文书
大学生党员个人对照检查材料范文
2014/09/25 职场文书
学校2016年全国助残日活动总结
2016/04/01 职场文书
Python中的套接字编程是什么?
2021/06/21 Python