Python接口测试框架实战与自动化进阶☝☝☝

 一、fiddler在工作中的运用

 1、如何抓接口

 抓紧手机端接口

  ①、在电脑终端输入:ipconfig ,找到电脑ip

  ②、打开手机,连接WiFi,进入WiFi详情,改用手动代理,将ip设置为电脑端的ip,端口默认(8888)

 

  ③、打开fiddler,找到并打开Fiddler Options ,选择Connections栏,做如下改动:

  

这样就可以尝试抓取接口了。

 二、unittest使用

python自带的包

1、unittest简单使用

使用unittest的test类:TestCase ,重载相关方法:

import unittest

class TestMethod(unittest.TestCase):

@classmethod

def setUpClass(cls):

print('重载setUpClass类方法,类实例化(初始化)时调用')

@classmethod

def tearDownClass(cls):

print('重载tearDownClass方法,所有方法执行完后调用')

def setUp(self):

print('重载setUp方法,每个test方法执行前都会调用')

def tearDown(self):

print('重载tearDown方法,每个test方法执行完成后都会调用')

def test_01(self):

print('测试方法,必须以 test 开头')

if __name__ == '__main__':

unittest.main()

2、unittest基本介绍

参考:http://www.php.cn/python-tutorials-358252.html

unittest提供了多个类:

__all__ = ['TestResult', 'TestCase', 'TestSuite',

'TextTestRunner', 'TestLoader', 'FunctionTestCase', 'main',

'defaultTestLoader', 'SkipTest', 'skip', 'skipIf', 'skipUnless',

'expectedFailure', 'TextTestResult', 'installHandler',

'registerResult', 'removeResult', 'removeHandler']

TestCase

setUp() # 在每个test执行前都要执行的方法

tearDown()  #在每个test执行后都要执行的方法。(不管是否执行成功)

setUpClass()  # 在一个测试类中在所有test开始之前,执行一次且必须使用到Testsuite(只有在TestSuite的run方法里面才对其调用)

tearDownClass()  # 在一个测试类中在所有test结束之后,执行一次且必须使用到Testsuite(只有在TestSuite的run方法里面才对其调用)

run()   # 这是unnitest的核心,逻辑也相对复杂,但是很好理解,具体自己看源码。所有最终case的执行都会归结到该run方法

# 还有一个重要的_resultForDoCleanups私有变量,存储TestResult的执行结果,这个在构建后面的skip用到

我们要明确TestCase类中所有的测试用例是独立的,其实每个testcase就是一个个TestCase类的实例对象,所以不要企图在某个test存储或改变一个变量,下个test中能用到,除非利用到setUpClass。我们看个例子:

import unittest

class Mydemo(unittest.TestCase):

def test1(self):

self.a=1

print ("i am test1 the value of a is {}".format(self.a))

def test2(self):

print ("i am test2 the value of a is {}".format(self.a))

if __name__ == '__main__':

unittest.main()

打印结果:

C:\Python27\python.exe D:/Moudle/module_1/test4.py

i am test1 the value of a is 1

.E

======================================================================

ERROR: test2 (__main__.Mydemo)

----------------------------------------------------------------------

Traceback (most recent call last):

File "D:/Moudle/module_1/test4.py", line 7, in test2

print ("i am test2 the value of a is {}".format(self.a))

AttributeError: 'Mydemo' object has no attribute 'a'

----------------------------------------------------------------------

Ran 2 tests in 0.001s

FAILED (errors=1)

上面就是说明TestCase类中所有的测试用例是独立的,每个testcase就是由TestCase实例化的一个独立的实例。如果要使用共享变量,使用全局变量或者类变量就好了。

借用类方法setUpClass与tearDownClass只执行一遍的特性,实现个小例子:启动时开启浏览器,执行结束时关闭浏览器:

import unittest

from  selenium import webdriver

class Mydemo(unittest.TestCase):

@classmethod

def setUpClass(cls):

cls.browser=webdriver.Firefox()

def test1(self):

'''登录'''

browser=self.browser

#do someting about login

def test2(self):

'''查询'''

browser = self.browser

# do someting about search

def test3(self):

'''提交数据'''

browser = self.browser

# do someting about submmit

@classmethod

def tearDownClass(cls):

browser=cls.browser

browser.close()

if __name__ == '__main__':

unittest.main()

 一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite中时也有四个测试用例。整个流程:

1

1、写好TestCase2、然后由TestLoader加载TestCase到TestSuite3、然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中4、我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例   这里加个说明,在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果(测试报告)

demo:

# test_mathfunc.py

import unittest

from mathfunc import *

class TestMathFunc(unittest.TestCase):

"""Test mathfuc.py"""

def test_add(self):

"""Test method add(a, b)"""

self.assertEqual(3, add(1, 2))

self.assertNotEqual(3, add(2, 2))

def test_minus(self):

"""Test method minus(a, b)"""

self.assertEqual(1, minus(3, 2))

def test_multi(self):

"""Test method multi(a, b)"""

self.assertEqual(6, multi(2, 3))

def test_divide(self):

"""Test method divide(a, b)"""

self.assertEqual(2, divide(6, 3))

self.assertEqual(3, divide(5, 2))

if __name__ == '__main__':

unittest.main()

执行结果:

.F..

======================================================================

FAIL: test_divide (__main__.TestMathFunc)

Test method divide(a, b)

----------------------------------------------------------------------

Traceback (most recent call last):

File "E:/AutomaticTest/Test_Framework/temp/test_mathfunc.py", line 24, in test_divide

self.assertEqual(3, divide(5, 2))

AssertionError: 3 != 2.5

----------------------------------------------------------------------

Ran 4 tests in 0.001s

FAILED (failures=1)

能够看到一共运行了4个测试,失败了1个,并且给出了失败原因,3 != 2.5 
这就是一个简单的测试,有几点需要说明的:

  1. 在第一行给出了每一个用例执行的结果的标识,成功是 .,失败是 F,出错是 E,跳过是 S。从上面也可以看出,测试的执行跟方法的顺序没有关系,test_divide写在了第4个,但是却是第2个执行的。
  2. 每个测试方法均以 test 开头,否则是不被unittest识别的。
  3. 在unittest.main()中加 verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果,即没有上面的结果中的第1行;如果设为 2,则输出详细的执行结果,如下:

# if __name__ == '__main__':

#     unittest.main(verbosity=2)

# 输出结果:

test_add (__main__.TestMathFunc)

Test method add(a, b) ... ok

test_divide (__main__.TestMathFunc)

Test method divide(a, b) ... FAIL

test_minus (__main__.TestMathFunc)

Test method minus(a, b) ... ok

test_multi (__main__.TestMathFunc)

Test method multi(a, b) ... ok

======================================================================

FAIL: test_divide (__main__.TestMathFunc)

Test method divide(a, b)

----------------------------------------------------------------------

Traceback (most recent call last):

File "E:/AutomaticTest/Test_Framework/temp/test_mathfunc.py", line 24, in test_divide

self.assertEqual(3, divide(5, 2))

AssertionError: 3 != 2.5

----------------------------------------------------------------------

Ran 4 tests in 0.001s

FAILED (failures=1)

批量测试TestCase:

1)不用 unittest.main() 执行,直接通过TextTestRunner来执行用例

import unittest

from test_mathfunc import TestMathFunc

if __name__ == '__main__':

suite = unittest.TestSuite()

tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")]

suite.addTests(tests)  # 将每个case用例都添加到TestSuite中

runner = unittest.TextTestRunner(verbosity=2)

runner.run(suite)  # 使用 TextTestRunner执行案例,默认结果会输出倒控制台

2)上述是使用addTest方法添加单个TestCase用例到TestSuite列表中,另外还能使用addTests + TestLoader 添加TestCase用例到TestSuite中

# 直接用addTest方法添加单个TestCase

suite.addTest(TestMathFunc("test_multi"))

# 使用addTests + unittest.TestLoader()方法结合

# loadTestsFromName(),传入'模块名.TestCase名'

suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc'))

suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc']))  # loadTestsFromNames(),类似,传入列表

# loadTestsFromTestCase(),传入TestCase

suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

需要注意的是:用TestLoader的方法是无法对case进行排序的。同时,suite中也可以套suite。

将测试结果输出到文件中 

 用例组织好了,但结果只能输出到控制台,这样没有办法查看之前的执行记录,我们想将结果输出到文件

import unittest

from test_mathfunc import TestMathFunc  # TestCase用例

if __name__ == '__main__':

suite = unittest.TestSuite()

suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

with open(r'D:\UnittestTextReport.txt', 'a') as f:

runner = unittest.TextTestRunner(stream=f,verbosity=2)  # 将结果输出到D盘下的 UnittestTextReport.txt 文件中

runner.run(suite)

跳过case

unittest也提供了几种方法,用于临时跳过某个case不执行

1)skip装饰器

执行结果:

可以看到总的test数量还是4个,但divide()方法被skip了。

skip装饰器一共有三个:

  1. unittest.skip(reason) :无条件跳过
  2. unittest.skipIf(condition, reason) :f当condition为True时跳过
  3. unittest.skipUnless(condition, reason) :当condition为False时跳过。

2)TestCase.skipTest()方法

执行结果:

用HTMLTestRunner输出漂亮的HTML报告 

 HTMLTestRunner是一个第三方的unittest HTML报告库,HTMLTestRunner.py文件的创建参考下面内容

demo:

import unittest

from test_mathfunc import TestMathFunc

from HTMLTestRunner import HTMLTestRunner

if __name__ == '__main__':

suite = unittest.TestSuite()

suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

with open(r'D:\HTMLReport.html', 'wb') as f:

runner = HTMLTestRunner(stream=f,

title='MathFunc Test Report',

description='generated by HTMLTestRunner.',

verbosity=2

)

runner.run(suite)

执行结果,控制台上可以看到:

ok test_add (test_mathfunc.TestMathFunc)

F  test_divide (test_mathfunc.TestMathFunc)

ok test_minus (test_mathfunc.TestMathFunc)

ok test_multi (test_mathfunc.TestMathFunc)

Time Elapsed: 0:00:00.002000

并且在D盘中生成了HTMLReport.html,打开如下:

 

HTMLTestRunner介绍

HTMLTestRunner url:http://tungwaiyip.info/software/HTMLTestRunner_0_8_2/HTMLTestRunner.py

1)进入链接,复制代码,重新生成一个HTMLTestRunner.py文件,将复制的代码copy进去

2)将HTMLTestRunner.py文件放到python安装目录的Lib目录下

3)项目需要用到时,将HTMLTestRunner.py文件导入到项目中使用即可

python3-HTMLTestRunner

三、mock服务入门到实战

1、什么是mock?

 mock在翻译过来有模拟的意思。这里要介绍的mock是辅助单元测试的一个模块。它允许您用模拟对象替换您的系统的部分,并对它们已使用的方式进行断言。

 实际生产中的项目有些会很复杂,对其进行单元测试的时候,会遇到以下问题:

  • 接口的依赖
  • 外部接口调用
  • 测试环境非常复杂

  单元测试应该只针对当前单元进行测试, 所有的内部或外部的依赖应该是稳定的, 已经在别处进行测试过的.此时使用mock 就可以对外部依赖组件实现进行模拟并且替换掉, 从而使得单元测试将焦点只放在当前的单元功能,而不再受外部依赖影响。

1

2

在Python2.x 中 mock是一个单独模块,需要单独安装

在Python3.x中,mock已经被集成到了unittest单元测试框架中,所以,可以直接使用

2、mock的使用

1)首先,来个简单的例子

①、创建module.py文件:

#module.py

class Count():

def add(self, a, b):

return a + b

②、对Count类的add方法进行测试,新建mock_test.py文件:

from unittest import mock

import unittest

from module import Count

class MockDemo(unittest.TestCase): #casetest用例

def test_add(self):

count = Count()

count.add = mock.Mock(return_value=13, side_effect=count.add)  # 使用Mock类实例化对象模拟add()方法

result = count.add(8, 8) # 真正调用add方法,返回数据16

print(result)

count.add.assert_called_with(8, 8)

self.assertEqual(result, 16)  # 判断结果是否相等

if __name__ == '__main__':

unittest.main()

解析:

 count.add = mock.Mock(return_value=13, side_effect=count.add):

  当side_effect为设置时(默认default),return_value设置的值会返回当作count.add方法的返回值,当side_effect被设置值时,return_value不起作用(side_effect参数和return_value是相反的,它给mock分配了可替换的结果,覆盖了return_value。简单的说,side_effect存在时一个模拟工厂调用将返回side_effect值,而不是return_value)

  上面代码,将side_effect的值设为count.add,此时count.add并未调用。

 result = count.add(8, 8):

  真正调用count.add方法,返回值:8

 count.add.assert_called_with(8, 8):

  调用add方法时,mock模拟了add方法,参数会被临时存储起来,通过这个方法会自动检查传入的参数是否与 count.add(8,8)中调用的参数保持一致,如果一致则通过,如果不一致则测试失败。

2)解决测试依赖

 前面的例子,只为了让大家对mock有个初步的印象。再接来,我们看看如何mock方法的依赖。

 例如,我们要测试A模块,然后A模块依赖于B模块的调用。但是,由于B模块的改变,导致了A模块返回结果的改变,从而使A模块的测试用例失败

①、新建function.py文件:

# function.py

def add_and_multiply(x, y):

addition = x + y

multiple = multiply(x, y)

return (addition, multiple)

def multiply(x, y):

return x * y

add_and_multiply(x,y),内部调用了multiply(x,y)函数,当multiply()内部代码改变时,add_and_multiply函数肯定会受到影响,此时即是add_and_multiply依赖于multiply函数。

②、新建mock_test.py文件:

import unittest

from unittest import mock

import function

class MyTestCase(unittest.TestCase):

@mock.patch("function.multiply")  # 装饰器,模拟类或对象。此时模拟multiply函数

def test_add_and_multiply2(self, mock_multiply):   # mock_multiply 即是 multiply函数

x = 3

y = 5

mock_multiply.return_value = 15  # 设定multiply的返回值,即multiply的返回值为15,固定不变

addition, multiple = function.add_and_multiply(x, y)  # 执行add_and_multiply函数,addition通过x+y得出数值为8 ,multiple通过multiply调用,此时被mock模拟,值固定为15

mock_multiply.assert_called_once_with(3, 5)

self.assertEqual(8, addition)

self.assertEqual(15, multiple)

if __name__ == "__main__":

unittest.main()

解析:

@mock.patch("function.multiply"):

 mock.patch()装饰/上下文管理器可以很容易地模拟类或对象在模块测试。在测试过程中,您指定的对象将被替换为一个模拟(或其他对象),并在测试结束时还原。这里模拟function.py文件中multiply()函数

def test_add_and_multiply2(self, mock_multiply)::

 在定义case测试用例中,将mock装饰的的multiply()函数(对象)重命名为 mock_multiply对象

mock_multiply.return_value = 15:

 设定mock_multiply对象的返回值为固定的15

ock_multiply.assert_called_once_with(3, 5): 检查ock_multiply方法的参数是否正确

 在测试代码中,我们调用了外部函数:add_and_multiply。它会调用内嵌的multiply函数。前面我们已经mock了multiply函数,此时通过add_and_multiply函数调用内部multiply函数,会被我们定义的mock对象取代。— 这个时候multiply函数被调用,传给它们的任何参数将被储存起来。顾名思义,mock对象的assert_called_once_with方法就是一个不错的捷径来验证某个对象是否被一组特定的参数调用过。如果被调用了,测试通过。反之,assert_called_once_with会抛出AssertionError的异常。即通过传入参数3 跟5 ,判断multiply之前是否引入这两个参数被调用过。

 好吧,我们遇到了很多实际问题。首先,我们通过mock将multiply函数从add_and_multiply中分离出来。这就意味着我们的单元测试只针对add_and_multiply的内部逻辑。只有针对add_and_multiply的代码修改将影响测试的成功与否。

其次,我们现在可以控制内嵌函数的输出,以确保外部函数处理了不同的情况。例如,add_and_multiply可能有逻辑条件依赖于multiply的返回值:比如说,我们只想在乘积大于10的条件下返回一个值。通过人为设定multiply的返回值,我们可以模拟乘积小于10的情况以及乘积大于10的情况,从而可以很容易测试我们的逻辑正确性。

最后,我们现在可以验证被mock的函数被调用的次数,并传入了正确的参数。由于我们的mock对象取代了multiply函数的位置,我们知道任何针对multiply函数的调用都会被重定向到该mock对象。当测试一个复杂的功能时,确保每一步都被正确调用将是一件非常令人欣慰的事情。

Python接口测试框架实战与自动化进阶☝☝☝的更多相关文章

  1. Python接口测试框架实战与自动化进阶✍✍✍

    Python接口测试框架实战与自动化进阶  整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看 ...

  2. Python接口测试实战4(上) - 接口测试框架实战

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  3. 《一头扎进》系列之Python+Selenium框架实战篇7 - 年底升职加薪,年终奖全靠它!Merry Christmas

    1. 简介 截止到上一篇文章为止,框架基本完全搭建完成.那么今天我们要做什么呢????聪明如你的小伙伴或者是童鞋一定已经猜到了,都测试完了,当然是要生成一份高端大气上档次的测试报告了.没错的,今天宏哥 ...

  4. python接口测试框架遇到的坑(一)excel数字转文本

    一.遇到的问题 python编写接口测试框架中,接口用例使用excel维护,其中预期值(code码的值)20000和实际值总是不一致,后来通过打印type发现一个是unicode,一个是float. ...

  5. 接口测试框架实战(三)| JSON 请求与响应断言

    关注公众号,获取测试开发实战干货合辑.本文节选自霍格沃兹<测试开发实战进阶>课程教学内容. 数据驱动就是通过数据的改变驱动自动化测试的执行,最终引起测试结果的改变.简单来说,就是参数化在自 ...

  6. 接口测试框架实战(一) | Requests 与接口请求构造

    1080×388 33.4 KB Requests 是一个优雅而简单的 Python HTTP 库,其实 Python 内置了用于访问网络的资源模块,比如urllib,但是它远不如 Requests ...

  7. Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  8. Python接口测试实战3(下)- unittest测试框架

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  9. Python接口测试实战1(上)- 接口测试理论

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

随机推荐

  1. MD5字符串加密

    MD5字符串加密 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 132 ...

  2. 2019年全国新课标I卷文理科数学LaTeX排版试题与解析

    整体分析,没有偏怪难题之分,中等题偏多,题目较往年有题型改动变化,但难度还称不上很难.具体内容贴上链接! https://mp.weixin.qq.com/s/WKXhCKI_-z3UT-zUwI23 ...

  3. windows安装mingw和LuaJIT

    1,安装mingw64 先下载mingw64压缩包(不建议下载exe安装包,在线安装太慢),地址如下: https://nchc.dl.sourceforge.net/project/mingw-w6 ...

  4. 大数据平台搭建 - cdh5.11.1 - hadoop集群安装

    一.前言 由于线下测试的需要,需要在公司线下(测试)环境搭建大数据集群. 那么CDH是什么? hadoop是一个开源项目,所以很多公司再这个基础上进行商业化,不收费的hadoop版本主要有三个,分别是 ...

  5. 判断是手机端还是PC短访问

    第一种:判断是手机访问还是PC访问 <script> function browserRedirect() { var sUserAgent = navigator.userAgent.t ...

  6. 深入理解Three.js中透视投影照相机PerspectiveCamera

    前言 在开始正式讲解透视摄像机前,我们先来理理three.js建模的流程.我们在开始创建一个模型的时候,首先需要创建我们模型需要的物体,这个物体可以是three.js中已经为我们封装好的,比如正方体, ...

  7. 30 (OC)* 数据结构和算法

    在描述算法时通常用o(1), o(n), o(logn), o(nlogn) 来说明时间复杂度 o(1):是最低的时空复杂度,也就是耗时/耗空间与输入数据大小无关,无论输入数据增大多少倍,耗时/耗空间 ...

  8. 快速获取dom到body左侧和顶部的距离,简单粗暴无bug-getBoundingClientRect

    获取dom到body左侧和顶部的距离-getBoundingClientRect 平时在写js的时候,偶尔会需要用js来获取当前div到 body 左侧.顶部的距离.网上查一查,有很多都是通过offs ...

  9. 【全网首创】修改 Ext.ux.UploadDialog.Dialog 源码支持多选添加文件,批量上传文件

    公司老框架的一个页面需要用到文件上传,本以为修改一个配置参数即可解决,百度一番发现都在说这个第三方插件不支持文件多选功能,还有各种各样缺点,暂且不讨论这些吧.先完成领导安排下来的任务. 任务一:支持多 ...

  10. C++ 生成随机数 srand()和rand()

    1. rand() rand(产生随机数)表头文件: #include<stdlib.h>定义函数 :int rand(void) 函数说明 :因为rand() 的内部实现是用线性同余法做 ...