接口测试 unittest实用教程

备注: 本文档针对 接口学习入门人群; ,中级 以及高级测试本篇文档请略过 ; 所有的实例数据来自于聚合数据平台 http://www.haoservice.com/apilist/

requests复习回顾

首先查看 request文件源码:

"""Constructs and sends a :class:`Request`.:param method: method for the new :class:`Request` object.:param url: URL for the new :class:`Request` object.:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.:param data: (optional) Dictionary or list of tuples ``[(key, value)]`` (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.:param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers to add for the file.:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.:param timeout: (optional) How many seconds to wait for the server to send data before giving up, as a float, or a :ref:`(connect timeout, read timeout)` tuple.:type timeout: float or tuple:param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.:type allow_redirects: bool:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.:param verify: (optional) Either a boolean, in which case it controls whether we verify the server's TLS certificate, or a string, in which case it must be a path to a CA bundle to use. Defaults to ``True``.:param stream: (optional) if ``False``, the response content will be immediately downloaded.:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.:return: :class:`Response` object:rtype: requests.ResponseUsage:: >>> import requests >>> req = requests.request('GET', 'http://httpbin.org/get') """

以下,对其中主要方法以及参数进行总结:

Requests.request(“请求方法的名字”,”URL”,可选参数)

1.params=字典 :

{ “id”:”1”,”name”:”张三”}

Python中的格式就字典 dict

Javascript 中叫 json

Params是网址中的参数

2.data = Text 字符串:

data 有以下两种方式表述:

;示例:

response = requests.request("post" ,"http://localhost/index.php?m=user&c=public&a=login",data= "url_forward=&username=zhangsan&password=zhangsan")

示例:

data = [("url_forward",""),("username","zhangsan"),("password","zhangsan")] response = requests.request("post" ,"http://localhost/index.php?m=user&c=public&a=login",data= data)

data是请求实体中的参数 ,请求实体类型

3.json=json

{"username":"xxx","password":"xxxpas"}

请求实体类型为 ,通过请求实体发送的

4.headers

5.cookies 6.file

7.auth 认证

通过信息头发送 ;

8.timeout 超时

9.请求方法:类似 ;

Request.get(“URL”,可选参数)Request.post(“URL”,可选参数)Request.delete(“URL”,可选参数)Request.put(“URL”,可选参数)

unittest

unittest是一个单元测试框架 ,类似于 java语言中的testng 和junit

作用: 用来组织和执行测试用例 ; 提供了常用的断言; 生成了比较丰富的日志信息(测试用例的数量, 测试结果执行的状态,以及测试执行的时间 ,错误用例的报错信息 …) ;提供了很多可扩展的东西(数据驱动测试是在unittest之上 ,生成测试报告也需要在unittest基础之上,) ;

文本不过多展开讲解, 基本每行代码都进行了注释 ;

一、Pyhon工作原理—— 核心概念:test case, testsuite, TestLoder,TextTestRunner,TextTestResult, test fixture

TestCase(测试用例): 所有测试用例的基类,它是软件 测试中最基本的组成单元。

一个test case就是一个测试用例,是一个完整的测试流程,包括测试前环境的搭建setUp,执行测试代码(run),以及测试后环境的还原(tearDown)。测试用例是一个完整的测试单元,可以对某一问题进行验证。

TestSuite(测试套件):多个测试用例test case集合就是TestSuite,TestSuite可以嵌套TestSuite

TestLoder:是用来加载 TestCase到TestSuite中,其中有几个loadTestsFrom_()方法,就是从各个地方寻找TestCase,创建他们的实例,然后add到TestSuite中,再返回一个TestSuite实例

TextTestRunner:是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。

TextTestResult:测试结果会保存到TextTestResult实例中,包括运行了多少用例,成功与失败多少等信息

TestFixture:又叫测试脚手,测试代码的运行环境,指测试准备前和执行后要做的工作,包括setUp和tearDown方法

二、测试流程

1.写好TestCase:一个class继承unittest.TestCase,就是一个测试测试用例,其中有多个以test开头的方法,那么 每一个这样的,在load的时候会生成一个TestCase实例。如果一个class中有四个test开头的方法,最后load到suite中时则有四个测试用例

2.由TestLoder加载TestCase到TestSuite

3.然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中。

说明:

a:通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者可以直接通过TextTestRunner来执行用例

b:Runner执行时,默认将结果输出到控制台,我们可以设置其输出到文件,在文件中查看 结果,也可以通过HTMLTestRunner将结果输出到HTML)

三、详细示例

快速入门实例:

新建unittestDemo.py文件 ;

# 1.导入 unittest, unittest是python内置的代码库, 不需要单独下载 ;import unittest# 2.继承unittest代码库中的 TestCase测试用例类 ;# 文件名一般首字母小写,类名首字母大写 , 文件名和类名一般就第一个字母不一样 ,# 在java中 继承使用extends关键字 ,python中使用 小括号()class UniittestDemo(unittest.TestCase): chrome = "谷歌浏览器" # 3. 重写父类中的 setUp 和 tearDown 方法 # 在 Python中 ,方法有一个关键字叫做 :def # self是 方法的第一个默认参数,self类似于 java中的 this关键字 ; # self 指的是当前类, 要想调用类中的属性或者方法, 前面需要加上self # setUp是建立的意思,类似于testng中的 beforeMethod(),负责测试用例之前的准备工作 ; def setUp(self): print(1) print(self.chrome) # tearDown 是拆除销毁的意思, 类似于testng中的 afterMethod() ,负责测试用例执行后的恢复工作; def tearDown(self): print(2) # 4. 编写 测试用例类 # 在 unittest中, 测试用例方法, 必须以test字符串开头, 类似于testng中,每个测试方法之上必须加@Test注解 ; def test_login(self): print(3) # 默认打印 1 3 2 , # Python中对格式的要求比 java严格,遇到冒号就必须缩进 4个空格 为准 def test_register(self): print(4) # 每次执行测试用例 ,都会重新执行一遍setUp(), tearDown()方法 ; # 如果光标在某个 方法内部运行程序, 那么只会运行该方法, # 一般在测试用例类外面,我们写一个 main关键字方法 , 类似于java中 public static void mian(String[] args){}# __name__ == '__main__'类似于主函数 ,在这段方法中写的代码,将不会被其他文件调用 ;(常用来做调试用)if __name__ == '__main__': # 默认执行当前文件中的测试用例方法 ; # unittest.main(UniittestDemo) unittest.main()

Output:

新建mainDemo.py文件

# 一般方法 ,普通方法只有被调用才能执行def read(): print(1)read()if __name__ == '__main__': read()# 这两种写法有什么区别 ??# main()下面的read方法只能在当前文件执行;# main上面的调用read方法 ,只要其他文件引用了这文件就会被执行;# 所以如果想要在类外部直接调用某个方法, 一般都是 if __name__ == '__main__': 方法中执行 ;

新建callMainDemo.py文件, 验证

# 导包快捷键 ,光标点击红色波浪线 ~ Alt+Enterfrom mainDemo import readread()

断言

所有的测试用例都必须包含断言,一个测试用例中,可以包含多个断言 ; 断言是由unittest单元自动化测试框架提供的 ;

新建answerRebotTest.py文件 ;

import unittestimport requestsclass AnswerRebotTest(unittest.TestCase): def setUp(self): self.url = "http://apis.haoservice.com/efficient/robot" def tearDown(self): print(self.result) def test_answer_rebot(self): parameters = {"info": "你好美男子", "address": "", "key": "3b1cf1120c2347d4b2c48149abb3e7b5"} response = requests.request("get",self.url ,params = parameters) self.result =response.json() # 第一个参数 期望结果 ,第二个参数 实际结果, 第三个参数 : 断言不通过时 ,提示信息 self.assertEqual('成功',self.result['reason']) self.assertEqual(0,self.result['error_code'] ) self.assertEqual(100000,self.result['result']['code']) # 编码代码时 ,要保持所有的测试用例都能 pass , 只有当回归测试或者数据驱动测试的时候,才有可能发现缺陷 ;if __name__ == '__main__': unittest.main()

数据驱动测试

读取csv文件的思路:

1.准备 csv文件2.导入csv 代码库

3.指定需要读取的csv文件的路径 ;

4.打开 csv文件 ,

5.通过csv代码库提供的方法 ,读取csv文件中的内容

6.打印csv文件中的内容

文件示例如下:

数据文件 :answerRebotTestData.csv

新建csvFileManager.py文件 ;

# 1. 准备 csv文件# 2. 导入csv 代码库import csv# 3. 指定需要读取的csv文件的路径 ;# 路径中的斜杠处理方式 有三种:# 1.用双反斜线代替反斜线 2.在整个字符串前加 字母r ,用 r表示该字符串不存在转移字符 ;3.将反斜线改为正斜线# 推荐 3, 使用正斜线可以跨平台path = r"D:\pyworkspace\apitest\data\answerRebotTestData.csv"# 4. 打开 csv文件 ,file = open(path,'r')# 5. 通过csv代码库提供的方法 ,读取csv文件中的内容content = csv.reader(file)# 6. 打印csv文件中的内容print(content)for row in content: print( row)# 测试用例类至少要调用这段代码, 才能得到csv文件中的数据# 必须要把这段代码封装成一个方法, # 详情见 csvFileManage2.py

测试用例如何接收读取的测试数据

1.导入ddt 即 data driver test,不是内置的代码库需要单独下载

cmd : pip install ddt

2.准备好读取csv文件的方法

该方法需要有一个返回值,返回csv文件中的数据,以二维列表的方式显示所有数据

新建csvFileManager2.py文件:

import csvdef readCsv(filename): path = 'D:/pyworkspace/apitest/data/' +filename +'.csv' file = open(path,"r") content = csv.reader(file) testdata = [] #申明一个空的列表 i = 0 for row in content: if i ==0: print("当前行为表头") else: testdata.append(row) i= i+1 return testdataif __name__ == '__main__': testdata = readCsv("answerRebotTestData") print(testdata)

3.在测试用例类上添加装饰器:

Python中的装饰器类似于java中的注解;

@ddt.ddt这个装饰器的作用 ,就是标志这个类采用ddt的方式提供测试数据

4.申明一个成员变量 ;

以 的返回值作为变量的值

5.在test方法上添加装饰器 :

6.修改方法的参数列表,增加一个列表类型参数

7.修改方法体 ,用变量名称替代原来的字符串常量

添加ddt后,修改后的answerRebotTest.py文件如下:

import unittest# 1.导入ddt 代码库import ddtimport requests# 2.为类添加装饰器import csvFileManage2@ddt.ddtclass AnswerRebotTest(unittest.TestCase): # 3.申明一个成员变量,读取csv文件中的数据 test_data = csvFileManage2.readCsv("answerRebotTestData") def setUp(self): self.url = "http://apis.haoservice.com/efficient/robot" def tearDown(self): print(self.result) # 4.为测试方法添加装饰器 @ddt.data(*variable) # 在python中 ,给列表前面加上* 号, 表示把列表拆分为多个元素 ; # example: list=[a,b,c] # *list = a,b,c # 这样就把一个list类型的元素, 拆分成了三个不同变量 ; # list中有几个元素, 就会拆分为几个变量 ; @ddt.data(*test_data) # 5.在方法的参数列表中添加一个形参 ,这个形参代表一组测试数据 ,就是excel中的每一行 ; def test_answer_rebot(self,row ): # 6.用row[n]代替原来写死的字符串常量 parameters = {"info": row[1], "address": row[2], "key": row[0]} response = requests.request("get",self.url ,params = parameters) self.result =response.json() # 第一个参数 期望结果 ,第二个参数 实际结果, 第三个参数 : 断言不通过时 ,提示信息 self.assertEqual(row[3],self.result['reason']) # row[4] 默认从csv文件读取出来的是 text ,需要 int()方法进行转换 ; self.assertEqual(int(row[4]),self.result['error_code'] ) # self.assertEqual(100000,self.result['result']['code']) # 编码代码时 ,要保持所有的测试用例都能 pass , 只有当回归测试或者数据驱动测试的时候,才有可能发现缺陷 ;if __name__ == '__main__': unittest.main()

批量执行测试用例

1.找出所有测试用例 :

test_suite = unittest.defaultTestLoader.discover(目录,文件名规则)

2.执行找出的测试用例 :

unittest.TextTestRunner().run(test_suite)

将要测试的py文件统一放在test_case目录 ;如图:

新建一个runallcases.py文件:

import unittestif __name__ == '__main__': # 1.找出所有的 unittest测试用例 # defaultTestLoader 默认的测试用例加载器 # 通过discover方法,设置规则 ,找出所有符合规则的测试用例 ; #.表示当前路径, run_all_case.py在项目的根节点位置 ; test_suite = unittest.defaultTestLoader.discover('./case_test', pattern='*.py', top_level_dir=None) # 执行找到的所有测试用例 ; # TextTestRunner()文本格式的测试用例器 ;用来执行测试用例的 , unittest.TextTestRunner().run(test_suite)

生成测试报告

1.导入HtmlTestRunner.py文件 (建议单独放在一个包内)

2.使用这个文件中的HtmlTestRunner类 ,代替unittest中的 TextTestRunner类,执行测试

通过类名, 一个是生成html格式的测试报告的测试用例执行器 , 另一个是生成文本日志格式 测试报告测试用例(只会打印在控制台) ;

3.现在生成一个新的文件,那么需要指定测试报告的保存路径 ;

在项目中创建一个report的文件夹

如图查看: 我在项目根目录下新建了package目录,将HTMLTestRunner.py文件拷贝进去 ,新建report目录,用来存放生成的测试报告 ;

使用HtmlTestRunner.py如何生成测试报告呢? 见以下代码:

使用 HtmlTestRunner生成测试报告, runallcase.py文件内容完整如下:

import unittestimport sysfrom package.HTMLTestRunner import HTMLTestRunnerif __name__ == '__main__': # 1.找出所有的 unittest测试用例 # defaultTestLoader 默认的测试用例加载器 # 通过discover方法,设置规则 ,找出所有符合规则的测试用例 ; #.表示当前路径, run_all_case.py在项目的根节点位置 ; test_suite = unittest.defaultTestLoader.discover('./case_test', pattern='*.py', top_level_dir=None) # # 2a .执行找到的所有测试用例 ; # TextTestRunner()文本格式的测试用例器 ;用来执行测试用例的 , # unittest.TextTestRunner().run(test_suite) # 2b .用 HtmlTestRunner代替TextTestRunner # stream 代表流的意思 , 这里要求填入一个2进制的文件流 # 3 .为生成的Html测试报告指定路径 path = "./report/" file_path = path + "ApiTestReport.html" file = open(file_path , "wb") HTMLTestRunner(stream=file, verbosity=1,title="ApiTest接口自动化测试报告",description="学会使用unittest测试框架 ,soeasy", tester = "Young").run(test_suite)

右键 run 后 ,查看多了 ApiTestReport.html文件:

使用chrome浏览器进行查看 ;

查看通过的详情 截图:

查看通过详情信息:

至此 .本篇完结 ;

拂晓时分

我伫立在阒无一人的街角

我熬过了夜晚

——博尔赫斯

一切经得起再度阅读的语言,

一定值得再度思索

——梭罗

你穿过世事朝我走来 迈出的每一步都留下了一座空城 这时,一支从来世射出的毒箭命定了我 唯一的退路 --仓央嘉措

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180826G14F3N00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券