《Web接口开发与自动化测试基于Python语言》--第13章
来源:互联网 发布:鉴知往来的意思 编辑:程序博客网 时间:2024/06/04 18:24
第13章 REST
REST同样属于Web Services技术范围。REST定义了一组体系框架原则,根据这些原则设计以系统资源为中心的Web 服务,包括使用不同语言编写的客户端如果通过HTTP处理和传输资源状态。REST可以说是近年来最主要的Web服务设计模型,基本取代了SOAP和WSDL。
13.1 RPD与REST
- RPC
Remote Procedure Call,远程过程调用。RPC风格的开发关注于服务器/客户端之间的方法调用,而并不关注基于哪个网络层的哪种协议。
RPC风格的代表是:XML-RPC、大Web 服务
XML-RPC
XML-RPC是一种使用XML格式封装的方法的调用,并使用HTTP协议作为传送机制的RPC风格的实现。
XML-RPC的请求方法是:HTTP协议的POST方法,请求和响应的数据格式均为XML。
测试用例管理系统TestLink的对外接口就是PHP开发的XML-RPC。
大Web服务
即Big Web Services,是基于SOAP+WSDL+UDDI等技术实现RPC风格的大型Web服务的统称。
- REST
Representational State Transfer,即表现层状态转化。
REST具有跨语言、跨平台的特点,它是一种遵循REST风格的Web Services。
如果一个架构符合REST原则,就称它为RESTful架构。
资源(Resources)
表现层其实指的是“资源”,所谓“资源”就是网络的一个实体,或者说是一个具体信息。可以用一个URI(统一资源定位符)来指向它,要想获取这个资源,只需要访问它的URI即可。
表现层(Representation)
“资源”是一种信息实体,它可以有多种外在表现形式,这种把“资源”具体呈现出来的形式,叫做它的“表现层”。
eg:文本既可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式、二进制格式来表现。
URI只代表资源的实体,不代表它的形式。
状态转化(State Transfer)
HTTP协议是一个无状态协议,所有的状态都保存在服务器端,客户端如果想要操作服务器,就必须通过某种手段,让服务器端发生“状态转化”,而这种转化是建立在表现层之上的,所以是“表现层状态转化”。
客户端用到的手段,只能是HTTP协议,具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT和DELETE。
GET:用来获取资源;
POST:用来新建资源(也可用于更新资源)
PUT:用来更新资源
DELETE:用来删除资源
综合以上内容,RESTful架构可以总结为:
每一个URI代表一种资源
客户端和服务器之间,传递这种资源的某种表现层
客户端通过四个HTTP动词,对服务器端资源进行操作,实现“表现层状态转化”
以上这些概念的一个包含关系:
SOA--Web Services--RPC--XML-RPC | |----Big Web Services--SOAP | |------WSDL | |------UDDI |-----------REST
13.2 Django REST Framework
顾名思义,是一套基于Django的REST风格的架构。
它具有以下特点:
功能强大、灵活,可以帮助你快速开发Web API
支持认证策略,包括OAuth 1a和OAuth 2
支持ORM和非ORM数据源的序列化
丰富的文档以及良好的社区支持
官方网址:http://www.django-rest-framework.org/
13.2.1 创建简单的API
安装Django REST Framework:
pip install djangorestframeworkpip install markdownpip install django-filter
安装好之后,创建一个新的项目django_rest,在项目下创建“api”应用:
django-admin startproject django_restcd django_restpython manage.py startapp api
进入django_rest,修改settings.py文件:
# Application definitionINSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'api',]# 在文件末尾添加如下信息REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', )}
rest_framework:为Django REST Framework应用;
api:为我们自己创建的应用;
DEFAULT_PERMISSION_CLASSES:默认的权限策略可以设置在全局范围内;
执行数据库迁移:python manage.py migrate
创建超级管理员帐户:python manage.py createsuperuser
Ps:这里我自己创建的是,admin、admin@mail.com、那啥+0
创建数据序列化,在api应用下创建serializers.py:
from django.contrib.auth.models import User, Groupfrom rest_framework import serializersclass UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email', 'groups')class GroupSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Group fields = ('url', 'name')
Serializers用于定义API的表现形式,如返回哪些字段、返回怎样的格式等,这里序列化Django自带的User和Group。
继续编辑视图文件:api/views.py
#! /usr/bin/python# -*- coding:utf-8 -*-from django.contrib.auth.models import User, Groupfrom rest_framework import viewsetsfrom api.serializers import UserSerializer, GroupSerializerfrom django.shortcuts import render# Create your views here.# ViewSets定义视图的展现形式class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited """ queryset = User.objects.all().order_by('-date_joined') serializer_class = UserSerializerclass GroupViewSet(viewsets.ModelViewSet): """ API endpoint that allows groups to be viewed or edited """ queryset = Group.objects.all() serializer_class = GroupSerializer
其中,ViewSets用于定义视图的展现形式,eg:返回哪些内容、需要做哪些权限处理。
在URL中会定义相应的规则到ViewSet,ViewSets则通过serializer_class找到对应的Serializers。这里将User和Group的所有对象赋予queryset,并返回这些值。在UserSerializer和GroupSerializer中定义要返回的字段。
继续编辑url文件:django_rest/urls.py
from django.conf.urls import url, includefrom django.contrib import adminfrom rest_framework import routersfrom api import views# Routers provide an easy way of automatically determining the URL conf.router = routers.DefaultRouter()router.register(r'users', views.UserViewSet)router.register(r'groups', views.GroupViewSet)# Wire up our API using automatic URL routing.# Additionally, we include login URLs for the browsable API.urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))]
因为使用的是ViewSets,所以可以使用routers类自动生成URL conf。
启动该服务:python manage.py runserver
,启动成功后,访问:http://127.0.0.1:8000的效果如下:
13.2.2 添加接口数据
通过前面创建的超级管理员账号登录,然后:
http://127.0.0.1:8000/groups/,通过该链接,添加用户组:test组、developer组
http://127.0.0.1:8000/users/,通过该链接,添加用户:tom、jack
13.2.3 测试接口
针对我们上面添加的用户、用户组的接口查询,使用Requests库编写测试用例:
#! /usr/bin/python# -*- coding:utf-8 -*-import unittestimport requestsclass UserTest(unittest.TestCase): '''用户查询测试''' def setUp(self): self.base_url = 'http://127.0.0.1:8000/users' self.auth = ('admin', 'admin123456') def test_user1(self): '''test user admin''' r = requests.get(self.base_url+'/1/', auth=self.auth) result = r.json() self.assertEqual(result['username'], 'admin') self.assertEqual(result['email'], 'admin@mail.com') def test_user2(self): '''test user tom''' r = requests.get(self.base_url+'/2/', auth=self.auth) result = r.json() self.assertEqual(result['username'], 'tom') self.assertEqual(result['email'], 'tom@mail.com') def test_user3(self): '''test user jack''' r = requests.get(self.base_url+'/3/', auth=self.auth) result = r.json() self.assertEqual(result['username'], 'jack') self.assertEqual(result['email'], 'jack@mail.com')class GroupsTest(unittest.TestCase): '''用户组查询测试''' def setUp(self): self.base_url = 'http://127.0.0.1:8000/groups' self.auth = ('admin', 'admin123456') def test_groups1(self): '''test groups test''' r = requests.get(self.base_url+'/1/', auth=self.auth) result = r.json() self.assertEqual(result['name'], 'test') def test_groups2(self): '''test groups developer''' r = requests.get(self.base_url+'/2/', auth=self.auth) result = r.json() self.assertEqual(result['username'], 'developer')if __name__ == '__main__': unittest.main()
注意:
- 请求接口的资源不是通过接口参数(?user=1)访问,而是通过URI路径(/1/)访问;
- 接口的访问需要用户签名,在发送get()请求时需要指定auth参数。
13.3 集成发布会系统API
通过Django REST Framework来实现发布会签到系统接口更简单。
13.3.1 添加发布会API
在我们创建的django_rest项目的基础上增加发布会和嘉宾的相关接口。
首先,创建模型,修改文件:api/models.py
#! /usr/bin/python# -*- coding:utf-8 -*-from __future__ import unicode_literalsfrom django.db import models# Create your models here.# 发布会class Event(models.Model): name = models.CharField(max_length=100) limit = models.IntegerField() status = models.BooleanField() address = models.CharField(max_length=200) start_time = models.DateTimeField('events time') create_time = models.DateTimeField(auto_now=True) def __str__(self): return self.name# 嘉宾class Guest(models.Model): event = models.ForeignKey(Event) realname = models.CharField(max_length=64) email = models.EmailField() sign = models.BooleanField() create_time = models.DateTimeField(auto_now=True) class Meta: unique_together = ('phone', 'event') def __str__(self): return self.realname
执行数据库迁移:
python manage.py makemigrations api
python manage.py migrate
继续添加发布会数据序列化,编辑文件:api/serializers.py
#!/usr/bin/python# -*- coding:utf-8 -*-from django.contrib.auth.models import User, Groupfrom rest_framework import serializersfrom api.models import Event, Guestclass UserSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = User fields = ('url', 'username', 'email', 'groups')class GroupSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Group fields = ('url', 'name')class EventSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Event fields = ('url', 'name', 'address', 'start_time', 'limit', 'status')class GuestSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Guest fields = ('url', 'realname', 'phone', 'email', 'sign', 'event')
继续定义发布会和嘉宾视图,编辑文件:api/views.py
#! /usr/bin/python# -*- coding:utf-8 -*-from django.contrib.auth.models import User, Groupfrom rest_framework import viewsetsfrom api.serializers import UserSerializer, GroupSerializer,EventSerializer, GuestSerializerfrom django.shortcuts import renderfrom api.models import Event, Guest# Create your views here.# ViewSets定义视图的展现形式class UserViewSet(viewsets.ModelViewSet): """ API endpoint that allows users to be viewed or edited """ queryset = User.objects.all().order_by('-date_joined') serializer_class = UserSerializerclass GroupViewSet(viewsets.ModelViewSet): """ API endpoint that allows groups to be viewed or edited """ queryset = Group.objects.all() serializer_class = GroupSerializerclass EventViewSet(viewsets.ModelViewSet): """ API endpoint that allows events to be viewed or edited """ queryset = Event.objects.all() serializer_class = EventSerializerclass GuestViewSet(viewsets.ModelViewSet): """ API endpoint that allows guests to be viewed or edited """ queryset = Guest.objects.all() serializer_class = GuestSerializer
继续添加URL配置,编辑文件:django_rest/urls.py
"""django_rest URL ConfigurationThe `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.10/topics/http/urls/Examples:Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))"""from django.conf.urls import url, includefrom django.contrib import adminfrom rest_framework import routersfrom api import views# Routers provide an easy way of automatically determining the URL conf.router = routers.DefaultRouter()router.register(r'users', views.UserViewSet)router.register(r'groups', views.GroupViewSet)router.register(r'events', views.EventViewSet)router.register(r'guests', views.GuestViewSet)# Wire up our API using automatic URL routing.# Additionally, we include login URLs for the browsable API.urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^', include(router.urls)), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))]
重启项目,访问后的效果如下:
13.3.2 测试接口
使用Django REST Framework开发的接口,除了可以使用GET方法查询接口数据外,还可以调用接口添加数据,并不需要关心接口插入数据的细节,只需要将接口请求改为POST即可。
使用Postman添加一条发布会接口,额,最近无法访问谷歌,这个工具也用不了,就使用了另外一个类似工具做测试:
13.4 soapUI测试工具
soapUI是一款针对REST和SOAP的功能和性能测试工具:https://www.soapui.org/
13.4.1 创建SOAP测试项目
Projects-New SOAP Project:
Project Name:MobileCodeWS
Initial WSDL:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
依次展开:MobileCodeWS–MobileCodeWSSoap–getMobileCodeInfo
双击:Request1,填写接口查询的手机号,点击运行按钮,即可得到结果。
注意: 新版本中要求填写userID,免费用户的userID是空白,默认为“?”问号,不修改的话会报错。
Ps:我已经把手机号去掉显示了。
13.4.2 创建REST测试项目
继续创建一个REST项目。
认证选项里各选项的含义:
Username:用于填写基本认证的用户名;
Password:用于填写基本认证的密码;
Domain:域名是基本认证的可选项,设置为空;
Pre-emptive auth:设置定义认证的行为;
Use global preference:用于定义HTTP设置为全局首选项;
Authenticate pre-emptively:仅适用于此请求,不需要等待身份验证时才发送凭据。
soapUI的官方文档:https://www.soapui.org/siapui-projects/soapui-projects.html
总结
Djanog REST Framework在实际使用中还是比较多的,针对于这块的测试方法,除了工具,就是代码测试的办法了,建议大家还是多对此部分内容进行深入学习。
- 《Web接口开发与自动化测试基于Python语言》--第13章
- 《Web接口开发与自动化测试基于Python语言》--第1章
- 《Web接口开发与自动化测试基于Python语言》--第2章
- 《Web接口开发与自动化测试基于Python语言》–第3章
- 《Web接口开发与自动化测试基于Python语言》–第4章
- 《Web接口开发与自动化测试基于Python语言》–第5章
- 《Web接口开发与自动化测试基于Python语言》--第7章
- 《Web接口开发与自动化测试基于Python语言》--第6章
- 《Web接口开发与自动化测试基于Python语言》--第8章
- 《Web接口开发与自动化测试基于Python语言》--第9章
- 《Web接口开发与自动化测试基于Python语言》--第10章
- 《Web接口开发与自动化测试基于Python语言》--第11章
- 《Web接口开发与自动化测试基于Python语言》--第12章
- 《Web接口开发与自动化测试基于Python语言》--第14章
- 《Web接口开发与自动化测试基于Python语言》--第15章
- 《Web接口开发与自动化测试(基于Python语言)》读书笔记(一)
- web自动化测试第1步:配置基于python语言的自动化测试环境
- 基于python+requests+unittest框架接口自动化测试设计开发
- 支付宝授权获取芝麻信用分数
- Java 语言基础
- Spring
- Mybatis maven项目配置以及案例
- 高级软件工程实验报告五
- 《Web接口开发与自动化测试基于Python语言》--第13章
- Java代码实现FTP服务器上传文件与下载文件
- AngularJs 入门购物车
- linux搭建MySQL主从复制,读写分离(完善篇)
- HTML基础--position 绝对定位 相对定位 锚点链接
- 密码的·分类
- 最优化基础:损失函数可视化、折页损失函数 & 梯度计算
- MVVM简单例子
- 17年10月自考--一直在路上~