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 正则表达式(转义问题)
Dec 15 Python
python杀死一个线程的方法
Sep 06 Python
浅析Python3爬虫登录模拟
Feb 07 Python
Pandas过滤dataframe中包含特定字符串的数据方法
Nov 07 Python
python替换字符串中的子串图文步骤
Jun 19 Python
wxPython实现画图板
Aug 27 Python
Matplotlib scatter绘制散点图的方法实现
Jan 02 Python
解决Jupyter无法导入已安装的 module问题
Apr 17 Python
python中shell执行知识点
May 06 Python
PyQt5如何将.ui文件转换为.py文件的实例代码
May 26 Python
Pygame框架实现飞机大战
Aug 07 Python
Pycharm自带Git实现版本管理的方法步骤
Sep 18 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代码优化及php相关问题总结
2006/10/09 PHP
windows下PHP APACHE MYSQ完整配置
2007/01/02 PHP
php array_intersect()函数使用代码
2009/01/14 PHP
如何在HTML 中嵌入 PHP 代码
2015/05/13 PHP
PHP 超级全局变量相关总结
2020/06/30 PHP
swoole锁的机制代码实例讲解
2021/03/04 PHP
javascript编程起步(第一课)
2007/01/10 Javascript
用jscript启动sqlserver
2007/06/21 Javascript
JQuery实现table行折叠效果以JSON做数据源
2014/05/26 Javascript
JavaScript中使用typeof运算符需要注意的几个坑
2014/11/08 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
2015/02/13 Javascript
jQuery插件简单实现方法
2015/07/18 Javascript
JavaScript实现可拖拽的拖动层Div实例
2015/08/05 Javascript
基于jQuery实现搜索关键字自动匹配功能
2020/03/26 Javascript
Node.js编写爬虫的基本思路及抓取百度图片的实例分享
2016/03/12 Javascript
AngularJS 过滤器的简单实例
2016/07/27 Javascript
vue2的todolist入门小项目的详细解析
2017/05/11 Javascript
jQuery为某个div加入行样式
2017/06/09 jQuery
Vue.js+cube-ui(Scroll组件)实现类似头条效果的横向滚动导航条
2019/06/24 Javascript
Vue+Element UI+vue-quill-editor富文本编辑器及插入图片自定义
2019/08/20 Javascript
jQuery实现动态加载瀑布流
2020/09/01 jQuery
vue3中轻松实现switch功能组件的全过程
2021/01/07 Vue.js
Python计算斗牛游戏概率算法实例分析
2017/09/26 Python
pyspark 读取csv文件创建DataFrame的两种方法
2018/06/07 Python
Python面向对象之类和对象实例详解
2018/12/10 Python
详解pandas库pd.read_excel操作读取excel文件参数整理与实例
2019/02/17 Python
Python基础学习之函数方法实例详解
2019/06/18 Python
Python3.0 实现决策树算法的流程
2019/08/08 Python
浅谈Python 敏感词过滤的实现
2019/08/15 Python
python交互模式基础知识点学习
2020/06/18 Python
计算机毕业大学生推荐信
2013/12/01 职场文书
8和9的加减法教学反思
2014/05/01 职场文书
无毒社区工作方案
2014/05/23 职场文书
上课睡觉万能检讨书
2015/02/17 职场文书
2015年学生会个人工作总结
2015/04/09 职场文书
Mysql表数据比较大情况下修改添加字段的方法实例
2022/06/28 MySQL