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查找函数f(x)=0根的解决方法
May 07 Python
python subprocess 杀掉全部派生的子进程方法
Jan 16 Python
Python IDLE 错误:IDLE''s subprocess didn''t make connection 的解决方案
Feb 13 Python
对Python3 序列解包详解
Feb 16 Python
Python3字符串encode与decode的讲解
Apr 02 Python
利用python在大量数据文件下删除某一行的例子
Aug 21 Python
Python实现TCP探测目标服务路由轨迹的原理与方法详解
Sep 04 Python
Django import export实现数据库导入导出方式
Apr 03 Python
Python偏函数Partial function使用方法实例详解
Jun 17 Python
python等待10秒执行下一命令的方法
Jul 19 Python
Python使用Selenium模拟浏览器自动操作功能
Sep 08 Python
使用pd.merge表连接出现多余行的问题解决
Jun 16 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
PHP安全编程之加密功能
2006/10/09 PHP
PHP 简单日历实现代码
2009/10/28 PHP
解析:使用php mongodb扩展时 需要注意的事项
2013/06/18 PHP
php删除数组元素示例分享
2014/02/17 PHP
PHP连接SQLServer2005的方法
2015/01/27 PHP
PHP实现的通过参数生成MYSQL语句类完整实例
2016/04/11 PHP
JQuery 操作Javascript对象和数组的工具函数小结
2010/01/22 Javascript
JavaScript版DateAdd和DateDiff函数代码
2012/03/01 Javascript
轻松创建nodejs服务器(6):作出响应
2014/12/18 NodeJs
JavaScript 面向对象与原型
2015/04/10 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
2016/08/18 Javascript
JS ES6中setTimeout函数的执行上下文示例
2017/04/27 Javascript
JS 中LocalStorage和SessionStorage的使用
2017/08/17 Javascript
关于定制FileField中的上传文件名称问题
2017/08/22 Javascript
Vue 中使用vue2-highcharts实现曲线数据展示的方法
2018/03/05 Javascript
vue项目中使用lib-flexible解决移动端适配的问题解决
2018/08/23 Javascript
Vue3.0结合bootstrap创建多页面应用
2019/05/28 Javascript
LayUi使用switch开关,动态的去控制它是否被启用的方法
2019/09/21 Javascript
JS实现音乐钢琴特效
2020/01/06 Javascript
vue和小程序项目中使用iconfont的方法
2020/05/19 Javascript
[01:22:10]Ti4 循环赛第二日 DK vs Empire
2014/07/11 DOTA
[01:05:41]EG vs Optic Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
Python实现简单登录验证
2016/04/13 Python
python实现微信跳一跳辅助工具步骤详解
2018/01/04 Python
python 简单照相机调用系统摄像头实现方法 pygame
2018/08/03 Python
用pyqt5 给按钮设置图标和css样式的方法
2019/06/24 Python
Django文件上传与下载(FileFlid)
2019/10/06 Python
python利用百度云接口实现车牌识别的示例
2020/02/21 Python
Python flask框架实现查询数据库并显示数据
2020/06/04 Python
python爬虫搭配起Bilibili唧唧的流程分析
2020/12/01 Python
日本7net购物网:书籍、漫画、杂志、DVD、游戏邮购
2017/02/17 全球购物
台湾母婴用品限时团购:妈咪爱
2018/08/03 全球购物
Omio中国:全欧洲低价大巴、火车和航班搜索和比价
2018/08/09 全球购物
写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数
2016/04/13 面试题
一劳永逸彻底解决pip install慢的办法
2021/05/24 Python
详解python网络进程
2021/06/15 Python