接口测试之RESTful

Posted Python自动化测试

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了接口测试之RESTful相关的知识,希望对你有一定的参考价值。

     REST又被称为表征性状态传输,它是指客户端与服务端之间传输信息的一种方式。在REST中并没有严格的标准和规范,它只是规定了一套对通信的约束,当然它也存在一些指导的约束,也就是说客户端与服务端关注的是分离,只要API改变。常见的RESTful系统形式由JSON组成,每个资源位于自己的URL路径上,并使用不同的HTTP请求方法进行操作。在这里还是以具体的案例来说明这部分的应用,在无涯课堂里面添加课程的信息,获取所有课程的信息,以及获取某一个课程的信息,和对课程信息进行修改,以及删除课程的信息。需要安装的第三方的库为:flask-restful,flask-httpauth,flask,安装成功后,就实现具体的案例代码。

      下面是添加课程信息,以及课程信息的操作,当然也添加了鉴权的认证方式(基本认证),见如下的源码:

#!/usr/bin/env python
# -*-coding:utf-8 -*-
from flask import Flask,make_response,jsonify,abort,request
from flask_restful import Api,Resource
from flask_httpauth import HTTPBasicAuth

app=Flask(__name__)
api=Api(app=app)
auth=HTTPBasicAuth()


@auth.get_password
def get_password(name):
if name=='wuya':
return 'admin'
@auth.error_handler
def authoorized():
return make_response(jsonify({'msg':"请认证"}),401)

@app.errorhandler(404)
def not_found(error):
return make_response(jsonify({'msg':'很抱歉,您访问的页面不存在'}))

books=[
{'id':1,'author':'wuya','name':'Python接口自动化测试实战','done':True},
{'id':2,'author':'无涯','name':'Selenium3自动化测试实战','done':False}
]

@app.route('/v1/api/books',methods=['GET'])
@auth.login_required
def get_books():
return jsonify(books)


@app.route('/v1/api/books',methods=['POST'])
@auth.login_required
def create_books():
if not request.json:
abort(400)
else:
book={
'id':books[-1]['id']+1,
'author':request.json.get('author'),
'name':request.json.get('name'),
'done':True
}
books.append(book)
return jsonify({'msg':'created ok '},201)


@app.route('/v1/api/book/<int:book_id>',methods=['GET'])
@auth.login_required
def get_book(book_id):
book=list(filter(lambda t:t['id']==book_id,books))
if len(book)==0:
abort(404)
else:
return jsonify({'status':0,'msg':'ok','datas':book})

@app.route('/v1/api/book/<int:book_id>',methods=['DELETE'])
@auth.login_required
def delete_book(book_id):
book=list(filter(lambda t:t['id']==book_id,books))
if len(book)==0:
abort(404)
else:
books.remove(book[0])
return jsonify({'status':1001,'msg':'课程信息已经删除成功'})

@app.route('/v1/api/book/<int:book_id>',methods=['PUT'])
@auth.login_required
def update_book(book_id):
book=list(filter(lambda t:t['id']==book_id,books))
if len(book)==0:
abort(404)
elif not request.json:
abort(400)
elif 'author' not in request.json and 'name' not in request.json:
abort(400)
elif 'done' not in request.json and type(request.json['done']) is not bool:
abort(400)
else:
book[0]['author']=request.json.get('author',book[0]['author'])
book[0]['name'] = request.json.get('name', book[0]['name'])
book[0]['done'] = request.json.get('done', book[0]['done'])
return jsonify({'status':1002,'msg':'课程信息更新成功','dats':book})


if __name__ == '__main__':
app.run(debug=True)

    其它的API就不再演示,对上面的代码进行改造,使用类的方式编写,定义的类必须继承Response类,在类中依据业务的操作编写不同的方法,比很添加课程信息POST请求,获取课程信息GET方法,见修改后的源码:

#!/usr/bin/env python
# -*-coding:utf-8 -*-
from flask import Flask,make_response,jsonify,abort,request
from flask_restful import Api,Resource
from flask_httpauth import HTTPBasicAuth

app=Flask(__name__)
api=Api(app=app)
auth=HTTPBasicAuth()


@auth.get_password
def get_password(name):
if name=='admin':
return 'admin'
@auth.error_handler
def authoorized():
return make_response(jsonify({'msg':"请认证"}),401)

books=[
{'id':1,'author':'wuya','name':'Python接口自动化测试实战','done':True},
{'id':2,'author':'无涯','name':'Selenium3自动化测试实战','done':False}
]

class Books(Resource):
decorators = [auth.login_required]

def get(self):
return jsonify(books)

def post(self):
if not request.json:
abort(400)
else:
book = {
'id': books[-1]['id'] + 1,
'author': request.json.get('author'),
'name': request.json.get('name'),
'done': True
}
books.append(book)
return jsonify({'msg': 'created ok '}, 201)


class Book(Resource):
decorators = [auth.login_required]

def get(self,book_id):
book = list(filter(lambda t: t['id'] == book_id, books))
if len(book) == 0:
abort(404)
else:
return jsonify({'status': 0, 'msg': 'ok', 'datas': book})

def post(self,book_id):
book = list(filter(lambda t: t['id'] == book_id, books))
if len(book) == 0:
abort(404)
elif not request.json:
abort(400)
elif 'author' not in request.json and 'name' not in request.json:
abort(400)
elif 'done' not in request.json and type(request.json['done']) is not bool:
abort(400)
else:
book[0]['author'] = request.json.get('author', book[0]['author'])
book[0]['name'] = request.json.get('name', book[0]['name'])
book[0]['done'] = request.json.get('done', book[0]['done'])
return jsonify({'status': 1002, 'msg': '更新课程信息成功', 'dats': book})

def post(self,book_id):
book = list(filter(lambda t: t['id'] == book_id, books))
if len(book) == 0:
abort(404)
else:
books.remove(book[0])
return jsonify({'status': 1001, 'msg': '课程的信息已经删除成功'})

api.add_resource(Books,'/v1/api/books')
api.add_resource(Book,'/v1/api/book/<int:book_id>')

if __name__ == '__main__':
app.run(debug=True)

修改的代码和上面的没多少差异,唯一不同的是通过类的方式编写,维护起来更加简单高效,依据业务的方法在类的方法中编写不同的业务就可以了。可能细心的同学注意到,修改课程信息和删除课程信息,我并没有使用PUT请求方法和DELETE请求方法,而是使用的是POST请求方法。这是因为HTTP/1.1的PUT方法和DELETE方法自身不带验证机制,任何人都可以对服务端进行操作,存在安全性的问题,因此一般不建议使用。当然如果配合WEB应用程序的验证机制,就可能开放使用PUT方法和DELETE方法。通过上面的案例代码,实现了一个简单的业务操作。在实际的工作应用中,可能会涉及到模拟程序,那么就可以使用flask-restful来进行应用,也可以采用unittest框架里面的mock,就看个人喜好而已。

    感谢您的阅读,后续会陆续更新文章。谢谢您的关注!如您对我的书或者课程感兴趣,可扫描二维码购买,谢谢您!