2018年10月6日 星期六javascript
15:05php
本文讨论的接口均是服务级的接口,不是代码级html
接口是什么前端
在讨论为何要作接口测试以前,咱们能够先稍微了解一下接口是什么?java
接口能够很不许确的理解成是与资源打交道,这个资源多是本系统的,也多是其余系统的。node
举个例子,假如咱们在开发1个bug管理系统,该系统须要拿到公司的全部开发和测试人员的信息,这样开发和测试人员不用注册均可以登陆进去了,这应该很好理解。python
那么这些人员的信息储存在哪里呢?通常存储在hr系统里。如今的需求更加明确了,咱们要到hr系统中去拿到人员信息,获取hr系统中的人员资源。git
怎么拿呢?不少种方式,能够直接把hr系统的数据库拷贝一份放到bug管理系统里,不过这样很差,由于数据的同步会有点麻烦;还能够直接连hr系统的数据库去查,这样也不太好,这样咱们就须要了解hr系统的数据存储结构和逻辑,一旦hr系统的数据字段发生改变,bug管理系统也要去该,以便同步。程序员
比较好的作法是,hr系统暴露一些接口,经过这些接口去获取人员信息资源,这样bug系统就不须要关心hr系统的数据存储实现了。github
这些接口多是这样的:
综上:接口能够理解成是不一样系统或模块之间资源交流方式;
接口测试其实是黑盒测试
做为黑盒测试,基本的测试思路是经过输入和输出判断被测系统或者对象的逻辑。
获取人员的信息,我须要把人员的用户名传给hr系统接口,这样hr系统的接口会返回给我用户的一些更加具体的信息。这里的输入是用户名,输出是用户的详细信息。
为何要作接口测试
既然是接口获取和操做资源的方式,而大部分系统和产品中,资源通常都是产品的核心,好比微信核心资源就是通信录关系链和聊天记录等,所以资源是必测的。
另外接口中大部分的内容是数据,经过数据的对比咱们能推测到系统和产品的逻辑,测接口就是测逻辑。
最后接口中的返回相对单纯,不像web页面,html代码中有太多ui的东西,ui最不稳定,变化太快,接口相对稳定一点点,可是里面的干扰信息更少,断言相对容易不少。
接口测试用例怎么写
仍是3a原则,这个我之前的回答里有。
接口测试笔试题
有哪些常见的接口
常见的接口测试工具
2018年10月7日 星期日
12:08
接口测试由浅入深的学习才能够尽可能减小挫败感,避免从入门到放弃的悲剧。
从入门到放弃其实最惋惜,毕竟花了那么多时间去学习,最后放弃掉,花费掉的青春就一去不复返了。
获取资源的接口
咱们先来看一下获取资源的接口。
v2ex是一个讨论区,也就是你们常说的论坛,这是一个小众的讨论区,基本上只有程序员光顾。
v2ex里有不少的节点,节点能够理解成是讨论板块,好比这个板块就是讨论python技术的。
v2ex提供了一些接口,可让咱们去获取v2ex站点的一些资源,好比讨论区的信息,热门帖子等,这很符合互联网的分享精神。
v2ex的api描述页面在这里, 文档相对简洁,基本上是给看得懂的人看的。
咱们仔细研究一下获取节点信息的接口。这个接口能够获取指定节点的名字,简介,URL 及头像图片的地址。
下面是这个接口的具体描述
得到指定节点的名字,简介,URL 及头像图片的地址。
https://www.v2ex.com/api/nodes/show.json
Method: GET
Authentication: None
接受参数:
name: 节点名(V2EX 的节点名全是半角英文或者数字)
例如:
https://www.v2ex.com/api/nodes/show.json?name=python
咱们从这个接口文档里能够得到哪些信息呢?换一句话说,咱们能不能经过接口文档去了解这个接口是作什么的呢?
接口分析
从上面的描述里,咱们能够获得下面一些信息
合起来,咱们应该能够获得这样的信息:
当咱们发送:https://www.v2ex.com/api/nodes/show.json?name=python,这个http的get请求给服务器以后,服务器应该返回相应的资源,那么这时候就须要探讨一下
如何查看接口的返回
咱们如今已经知道了这个接口的状况了,如何查看接口的返回呢?
咱们可使用一些辅助工具帮助咱们进行接口的调用,查看接口返回,最简单的跨平台调试工具推荐使用postman
2018年10月7日 星期日
12:08
关于postman
postman是跨平台的接口调试及测试工具,很是适合初学者使用。
安装postman
请选择相应的版本下载,windows版下载完成后双击安装就行了。
postman的界面
发送第一个请求
咱们发送上一节里提到的获取v2ex节点信息的api。
https://www.v2ex.com/api/nodes/show.json?name=python
具体步骤以下
postman是如何工做的
从原理图上能够看出,postman发送请求给服务器,而后从服务器接受响应,最后在postman中展现出来。
服务器响应
上图就是服务器的响应详情,这里包含了一些重要信息
json字符串
有基础的同窗能够看出来,响应的主体是json格式的字符串,那么什么是json格式字符串呢?下一节咱们将详细讲解。
2018年10月7日 星期日
12:09
官方解释
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用彻底独立于语言的文本格式,可是也使用了相似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
什么是JSON
首先json是字符串。
你们都知道,字符串是用来传递信息的。json字符串实际上就是一种规定了格式的字符串,
经过这种格式,咱们能够在不一样的编程语言之间互相传递信息,好比咱们能够把javascript的对象转换成json传递给java,这样java能够反解析出java语言自身表明的对象;同理,咱们能够把java对象转成json,经过解析json,python语言能够把json转成是自身的dict或者是list,json统一了交流的格式,使得信息能够在不一样的语言间顺畅传递。
JSON解析的简单例子
好比,咱们能够把json字符串转成python语言的dict
#coding: utf-8
import json
json_str = """
{
"id" : 90,
"name" : "python",
"url" : "http://www.v2ex.com/go/python",
"title" : "Python",
"title_alternative" : "Python",
"topics" : 7646,
"stars" : 4862,
"header" : "这里讨论各类 Python 语言编程话题,也包括 Django,Tornado 等框架的讨论。这里是一个可以帮助你解决实际问题的地方。",
"footer" : null,
"created" : 1278683336,
"avatar_mini" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_mini.png?m=1504080972",
"avatar_normal" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_normal.png?m=1504080972",
"avatar_large" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_large.png?m=1504080972"
}
"""
res = json.loads(json_str)
print(res['id']) # 90
print(res['name']) # python
print(res['url']) # http://www.v2ex.com/go/python
2018年10月7日 星期日
12:09
3A原则本来是单元测试用例编写时应该遵循的基本原则,不过咱们能够扩展到接口的自动化测试用例编写中来。
咱们首先看一下3A原则在每一层自动化测试中的具体应用。
单元测试用例
给一个例子(c#)
[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
// arrange
double currentBalance = 10.0;
double withdrawal = 1.0;
double expected = 9.0;
var account = new CheckingAccount("JohnDoe", currentBalance);
// act
account.Withdraw(withdrawal);
double actual = account.Balance;
// assert
Assert.AreEqual(expected, actual);
}
服务间的接口测试用例
服务间的接口测试其实是黑盒测试,3A原则也适用于这种测试用例的编写
举个例子(python)
def test_get_task_by_id(self):
# arrange
create_task_res = self.create_task('test', 'desc')
new_id = create_task_res['id']
# act
url_for_get_by_id = self.ip + '/api/tasks/' + str(new_id)
res = requests.request("GET", url_for_get_by_id).json()
# assert
self.assertEqual(res['id'], new_id)
手工测试用例
手工的功能测试用例也能够用3A原则来编写。
举个例子
# arrange and act
打开chrome浏览器并跳转至http://localhost/wordpress/wp-login.php
在用户名文本框中输入admin
在密码文本框中输入admin
点击登录按钮
# assert
浏览器跳转到http://localhost/wordpress/wp-admin/
右上角出现“你好,admin”字样
总结
总之对于接口的自动化测试用例说来,遵循3A原则就意味着
2018年10月7日 星期日
12:10
在咱们真正的编写测试用例以前,咱们须要了解一下测试框架。
unittest是python自带的单元测试框架,尽管其主要是为单元测试服务的,但咱们也能够用它来作接口的自动化测试。
unittest框架为咱们编写用例提供了以下的能力
简单的例子
import unittest
class StringTestCase(unittest.TestCase):
def setUp(self):
# Arrange
self.test_string = "This is a string"
def testUpper(self):
# Act and Assert
self.assertEqual("THIS IS A STRING", self.test_string.upper())
if __name__ == '__main__':
unittest.main()
剖析
import unittest
导入unittest库,不导入就没办法使用,比如手机若是要使用某个app就必须先安装该app同样,是套路,记住就好。
class StringTestCase(unittest.TestCase):
定义测试类,初学者看到这一行就惧怕,其实大可没必要。这仍是套路,测试类的名字你能够随意取,固然了首字母最好大写,这样更符合规范一些。全部的测试类都必须直接或间接的继承自unittest.TestCase类。总之,这仍是套路,记住就好。
def setUp(self):
# Arrange
self.test_string = "This is a string"
继续套路。setUp(self)方法是一个钩子方法,在每一个测试用例执行以前都会执行一次,是作数据初始化的好地方。
在上面的例子里,咱们为每个测试方法都定义了被测对象,self.test_string
def testUpper(self):
# Act and Assert
self.assertEqual("THIS IS A STRING", self.test_string.upper())
套路继续。这里定义了一个名为testUpper的测试方法,这个方法就是一个测试用例。
注意,只有方法名以test开头的方法才是测试用例
self.assertEqual是一个断言方法,做用是若是第一个参数跟第二个参数相等,那么用例经过,不然用例失败,并在测试报告中打印出错误缘由。上面的例子里,咱们判断self.test_string.upper()方法会将"This is a string"字符串转换成"THIS IS A STRING"
if __name__ == '__main__':
unittest.main()
最后依然是套路,上面的代码表示,若是直接执行该python文件的话,就运行全部的测试类里的测试用例,也就是运行全部的以test开头的方法。
总结
使用unittest的话须要记住下面的几点
2018年10月7日 星期日
12:10
requests库能够极大的简化咱们发送http请求及获取响应的代码,简洁而优雅。
简单示例
>>> import requests
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
上面的例子相信你们很容易看明白,在咱们作接口自动化测试的时候,咱们每每使用requests的提供的接口发送请求和获取响应,并根据响应类型将响应转换成python自建的数据结构。好比上面的例子里,咱们将响应的json字符串转换成了python的dict。
安装
快速开始
划重点
英文很差的同窗能够参考中文文档的相关章节。
2018年10月7日 星期日
12:10
前面铺垫了不少的基础知识,掌握基础知识是作基于http接口自动化测试的前提,不建议直接跳过。
前提条件
学习本节须要有一些前提条件
用例描述
在认识测试对象这一节里有过描述。
得到指定节点的名字,简介,URL 及头像图片的地址。
https://www.v2ex.com/api/nodes/show.json
Method: GET
Authentication: None
接受参数:
name: 节点名(V2EX 的节点名全是半角英文或者数字)
例如:
https://www.v2ex.com/api/nodes/show.json?name=python
# 响应
{
"id" : 90,
"name" : "python",
"url" : "http://www.v2ex.com/go/python",
"title" : "Python",
"title_alternative" : "Python",
"topics" : 7669,
"stars" : 4870,
"header" : "这里讨论各类 Python 语言编程话题,也包括 Django,Tornado 等框架的讨论。这里是一个可以帮助你解决实际问题的地方。",
"footer" : null,
"created" : 1278683336,
"avatar_mini" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_mini.png?m=1504279401",
"avatar_normal" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_normal.png?m=1504279401",
"avatar_large" : "//v2ex.assets.uxengine.net/navatar/8613/985e/90_large.png?m=1504279401"
}
使用postman调试接口
在写用例以前,咱们先在postman里把接口调通,你们能够参考以前这篇
而后选择右上角的Code菜单,以下图所示
选择导出为python requests的代码,拷贝到系统剪切板,以下图所示
导出的代码应该是这个样子的
import requests
url = "https://www.v2ex.com/api/nodes/show.json"
querystring = {"name":"python"}
headers = {
'cache-control': "no-cache",
'postman-token': "a596dcc5-ab8b-8456-79c7-94a6ac11378e"
}
response = requests.request("GET", url, headers=headers, params=querystring)
print(response.text)
使用unittest重构代码
导出的代码只是3A里的Arrange和Act,咱们使用unittest来重构代码
新建文件v2ex_api_case.py
import requests
import unittest
class V2exAPITestCase(unittest.TestCase):
def test_node_api(self):
url = "https://www.v2ex.com/api/nodes/show.json"
querystring = {"name":"python"}
response = requests.request("GET", url, params=querystring).json()
self.assertEqual(response['name'], 'python')
self.assertEqual(response['id'], 90)
if __name__ == '__main__':
unittest.main()
运行用例
使用下面的命令能够运行用例
python v2ex_api_case.py
运行结果
.
---------------------------------------
Ran 1 test in 0.437s
OK
总结
2018年10月7日 星期日
12:11
使用场景
前端客户端团队和后端服务端团队每每节奏是不一致的。前端不少状况下须要等待后台的api开发完成后才能进行开发联调和测试,这种先后端不对称就形成了先后端团队节奏不一致,从而形成整个项目/产品交付/发布延期。
有一种解决方案的思路是先后端先约定好后端提供的api接口的细节,前端人员自行先模拟出这些后端的实现,固然这些实现是假的,不过前端能够去调用这些假的实现,并且能拿到返回,这样一来前端就不须要等待后端开发完成才开始工做了。
可是这样仍是会有问题,前端实现的假的api没办法迅速反映出后端的变化。简单来讲就是后端可能在约定好的api接口上进行了些许修改,而没有知会前端人员,这样前端的假的api实现并无相应更新,在正式联调时就会出现问题。
像这种假的api实现,无论是前端实现的仍是后端去实现的,咱们能够称之为mock server。
契约测试
因为先后端每每有一些信息不对称,致使约定的api可能在先后端都会发生变化,因此保证先后端的一致性就成了一个挑战。
这时候有人提出了契约测试,大体思想是先后端共用一份契约,约定了api的细节,先后端的任何变化都须要先修改契约,而后经过契约去通知先后端团队,统一更新实现。这也是契约精神的表现。
若是为契约测试设置一种测试工具的话,我会规划下面一些特性
2018年10月7日 星期日
12:11
flask
flask是python实现的简单的web框架,与django互补。
flask教程
如何理解flask
最简单的例子
from flask import Flask
app = Flask(__name__)
@app.route("/") # 路由
def hello(): # handler
return "Hello World!"
实现mocked smile task api
获取全部的任务
GET /api/tasks # get all tasks
查看一个任务的详情
GET /api/tastks/:task_id # get a task with task_id
完成一个任务
PUT /api/tastks/:task_id # complete a task
代码
from flask import Flask, jsonify, g
import copy
app = Flask(__name__)
@app.before_request
def set_up_data():
g.data = [
{'id': 1, 'title': 'task 1', 'desc': 'this is task 1'},
{'id': 2, 'title': 'task 2', 'desc': 'this is task 2'},
{'id': 3, 'title': 'task 3', 'desc': 'this is task 3'},
{'id': 4, 'title': 'task 4', 'desc': 'this is task 4'},
{'id': 5, 'title': 'task 5', 'desc': 'this is task 5'}
]
g.task_does_not_exist = {"msg": "task does not exist"}
@app.route('/api/tasks')
def get_all_tasks():
return jsonify(g.data)
@app.route('/api/tasks/<int:task_id>')
def get_task(task_id):
if task_id > 0 and task_id <= len(g.data):
return jsonify(g.data[task_id])
else:
return jsonify(g.task_does_not_exist)
@app.route('/api/tasks/<int:task_id>', methods=['PUT'])
def complete_task(task_id):
if task_id > 0 and task_id <= len(g.data):
tmp = copy.deepcopy(g.data[task_id])
tmp['done'] = True
return jsonify(tmp)
else:
return jsonify(g.task_does_not_exist)
运行
set FLASK_APP=smile_task_mock_server.py
flask run
* Serving Flask app "smile_task_mock_server"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
浏览器打开localhost:5000就行了