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单例模式实例分析
Jan 14 Python
使用Python中的线程进行网络编程的入门教程
Apr 15 Python
Python中splitlines()方法的使用简介
May 20 Python
Python面向对象之继承和组合用法实例分析
Aug 27 Python
浅析python继承与多重继承
Sep 13 Python
在Python 中同一个类两个函数间变量的调用方法
Jan 31 Python
Python人脸识别第三方库face_recognition接口说明文档
May 03 Python
Django 全局的static和templates的使用详解
Jul 19 Python
OpenCV python sklearn随机超参数搜索的实现
Jan 17 Python
python3利用Axes3D库画3D模型图
Mar 25 Python
Tensorflow tf.nn.atrous_conv2d如何实现空洞卷积的
Apr 20 Python
2021年pycharm的最新安装教程及基本使用图文详解
Apr 03 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
火车头采集器3.0采集图文教程
2007/03/17 PHP
PHP 分页类(模仿google)-面试题目解答
2009/09/13 PHP
浅谈php serialize()与unserialize()的用法
2013/06/05 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
2016/01/08 PHP
教你php如何实现验证码
2016/01/20 PHP
PHP实现对二维数组某个键排序的方法
2016/09/14 PHP
Thinkphp3.2实用篇之计算型验证码示例
2017/02/09 PHP
php 如何设置一个严格控制过期时间的session
2017/05/05 PHP
PHP编程计算两个时间段是否有交集的实现方法(不算边界重叠)
2017/05/30 PHP
一个实用的php验证码类
2017/07/06 PHP
yii2.0框架数据库操作简单示例【添加,修改,删除,查询,打印等】
2020/04/13 PHP
javascript中的undefined 与 null 的区别  补充篇
2010/03/17 Javascript
用Javascript来生成ftp脚本的小例子
2013/07/03 Javascript
jQuery 处理页面的事件详解
2015/01/20 Javascript
在Javascript中处理数组之toSource()方法的使用
2015/06/09 Javascript
JavaScript中eval()函数用法详解
2015/12/14 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
ajax前台后台跨域请求处理方式
2018/02/08 Javascript
js实现鼠标单击Tab表单切换效果
2018/05/16 Javascript
vue watch普通监听和深度监听实例详解(数组和对象)
2018/08/16 Javascript
Vue中 key keep-alive的实现原理
2018/09/18 Javascript
layui table单元格事件修改值的方法
2019/09/24 Javascript
[01:10:24]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第一场 2月28日
2021/03/11 DOTA
Python实现二叉树结构与进行二叉树遍历的方法详解
2016/05/24 Python
pytorch数据预处理错误的解决
2020/02/20 Python
美国婚礼装饰和活动用品批发供应商:Event Decor Direct
2018/10/12 全球购物
中国一家综合的外贸B2C电子商务网站:DealeXtreme(DX)
2020/03/10 全球购物
如何进行有效的自我评价
2013/09/27 职场文书
音乐表演专业毕业生求职信
2013/10/14 职场文书
计算机专业自荐信
2014/05/24 职场文书
ktv周年庆活动方案
2014/08/18 职场文书
尼克胡哲观后感
2015/06/08 职场文书
2015年终个人政治思想工作总结
2015/11/24 职场文书
铁头也玩根德 YachtBoy YB-230......
2022/04/05 无线电
Vue Mint UI mt-swipe的使用方式
2022/06/05 Vue.js