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解析json实例方法
Nov 19 Python
Django中URLconf和include()的协同工作方法
Jul 20 Python
Python 实现数据库(SQL)更新脚本的生成方法
Jul 09 Python
pygame 精灵的行走及二段跳的实现方法(必看篇)
Jul 10 Python
解决pandas中读取中文名称的csv文件报错的问题
Jul 04 Python
python利用pandas将excel文件转换为txt文件的方法
Oct 23 Python
Python List cmp()知识点总结
Feb 18 Python
python+mysql实现教务管理系统
Feb 20 Python
对django 模型 unique together的示例讲解
Aug 06 Python
python如何将多个PDF进行合并
Aug 13 Python
Python3操作MongoDB增册改查等方法详解
Feb 10 Python
Python 实现将某一列设置为str类型
Jul 14 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
Codeigniter框架实现获取分页数据和总条数的方法
2014/12/05 PHP
thinkPHP5分页功能实现方法分析
2017/10/25 PHP
php实现的rc4加密解密类定义与用法示例
2018/08/16 PHP
JavaScript 使用技巧精萃(.net html
2009/04/25 Javascript
javaScript实现浮点数转十六进制字符
2013/10/29 Javascript
js弹出确认是否删除对话框
2014/03/27 Javascript
javascript运动详解
2015/07/06 Javascript
《JavaScript函数式编程》读后感
2015/08/07 Javascript
js实现文本框只允许输入数字并限制数字大小的方法
2015/08/19 Javascript
JS实现点击按钮获取页面高度的方法
2015/11/02 Javascript
Bootstrap carousel轮转图的使用实例详解
2016/05/17 Javascript
javascript表单控件实例讲解
2016/09/13 Javascript
Node.js + Redis Sorted Set实现任务队列
2016/09/19 Javascript
vue短信验证性能优化如何写入localstorage中
2018/04/25 Javascript
解决vue项目打包后提示图片文件路径错误的问题
2018/07/04 Javascript
浅谈vue中$bus的使用和涉及到的问题
2020/07/28 Javascript
javascript中call,apply,bind的区别详解
2020/12/11 Javascript
vue keep-alive的简单总结
2021/01/25 Vue.js
jQuery实现鼠标拖动图片功能
2021/03/04 jQuery
[06:53]DOTA2每周TOP10 精彩击杀集锦vol.3
2014/06/25 DOTA
[01:06:32]DOTA2上海特级锦标赛D组资格赛#1 EG VS VP第一局
2016/02/28 DOTA
python sort、sort_index方法代码实例
2019/03/28 Python
python openvc 裁剪、剪切图片 提取图片的行和列
2019/09/19 Python
python psutil监控进程实例
2019/12/17 Python
给Python学习者的文件读写指南(含基础与进阶)
2020/01/29 Python
Python faker生成器生成虚拟数据代码实例
2020/07/20 Python
Pycharm及python安装详细教程(图解)
2020/07/31 Python
德国最大的拼图在线商店:Puzzle.de
2016/12/17 全球购物
BIBLOO波兰:捷克的一家在线服装店
2018/03/09 全球购物
Aquatalia官网:意大利著名鞋履品牌
2019/09/26 全球购物
《黄河颂》教学反思
2014/02/07 职场文书
导游欢迎词范文
2015/01/23 职场文书
护士个人年度总结范文
2015/02/13 职场文书
交心谈心活动总结
2015/05/11 职场文书
新学期家长寄语2016
2015/12/03 职场文书
《三国志》赏析
2019/08/27 职场文书