Python接口測試實戰5(下) - RESTful、Web Service及Mock Server

本節內容

  • REST及RESTful API
  • Web Service
  • XML解析
  • Mock Server

REST及RESTful API

參考連接: https://blog.csdn.net/lch2848508/article/details/72729658html

REST:表述性狀態轉移或表現層狀態轉移,「表現」及每一個接口地址(URI)都表現爲(視爲)一個資源對象(文本資源、圖片資源、服務資源),狀態轉移指經過POST/PUT方法發送完整的新狀態信息來更改資源對象的狀態
如某https://api.***.com/user資源狀態爲{"name": "Kaka", "age": 30},咱們經過POST/PUT請求發送新狀態{"name": "Kaka", "age": 18}來更新對象信息,完成狀態轉移前端

URI 與URL的區別:URL值包含協議的連接,如https://www.baidu.com, 還有一種相對連接叫URN,如/doc/1.html,這兩種都能惟必定位一個資源,URI(統一資源定位符)包含URL和URNjava

RESTful API是一種接口設計風格或規範,主要有如下特色:node

  • 統一使用https協議
  • 接口使用專用的api域名 https://api.example.com/
  • 接口分版本管理 https://api.example.com/v1/
  • 路徑又稱"終點"(endpoint),表示API的具體網址,路徑中只能包含名詞(表明資源對象),可使用複數來表明多個一個資源集合https://api.example.com/v1/zoos
  • 同一個接口提供多種請求方法,GET獲取資源信息,POST新建或更新資源,PUT/PATCH更新資源,DELETE刪除資源
  • 能夠經過url參數過濾信息 https://api.example.com/v1/zoos?limit=10 # 獲取前10個
  • 儘可能使用JSON, 避免使用XML
  • 身份認證推薦使用OAuth2.0,或Basic Auth,token等,避免使用Cookie和Session(RESTful強調無狀態的設計)

示例:python

https://api.github.com
受權 Basic Auth (superhin001, ***) 或 Oauth 2.0 Access Token: 1c4f679300f29ee4e7041028d49e504b9da145b1git

GET https://api.github.com/user 獲取用戶信息
github

GET https://api.github.com/user

POST/PATCH https://api.github.com/user 修改用戶信息
json

POST https://api.github.com/user

POST/PATCH 數據
{
    "login": "superhin001", "id": 21163682, "node_id": "MDQ6VXNlcjIxMTYzNjgy", "avatar_url": "https://avatars3.githubusercontent.com/u/21163682?v=4", "gravatar_id": "", "url": "https://api.github.com/users/superhin001", "html_url": "https://github.com/superhin001", "followers_url": "https://api.github.com/users/superhin001/followers", "following_url": "https://api.github.com/users/superhin001/following{/other_user}", "gists_url": "https://api.github.com/users/superhin001/gists{/gist_id}", "starred_url": "https://api.github.com/users/superhin001/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/superhin001/subscriptions", "organizations_url": "https://api.github.com/users/superhin001/orgs", "repos_url": "https://api.github.com/users/superhin001/repos", "events_url": "https://api.github.com/users/superhin001/events{/privacy}", "received_events_url": "https://api.github.com/users/superhin001/received_events", "type": "User", "site_admin": false, "name": "我是韓老師", "company": null, "blog": "", "location": null, "email": "superhin@126.com", "hireable": null, "bio": null, "public_repos": 3, "public_gists": 0, "followers": 0, "following": 0, "created_at": "2016-08-22T01:12:32Z", "updated_at": "2018-09-14T02:33:43Z", "private_gists": 0, "total_private_repos": 0, "owned_private_repos": 0, "disk_usage": 45430, "collaborators": 0, "two_factor_authentication": false, "plan": { "name": "free", "space": 976562499, "collaborators": 0, "private_repos": 0 } } 

GET https://api.github.com/user/keys 獲取用戶全部SSH-Key信息
flask

GET https://api.github.com/user/keys

POST https://api.github.com/user/keys 新建Key
後端

POST https://api.github.com/user/keys

POST 數據

{
        "id": 30742411, "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDfsTJs7mNWstJ+tO6O1jQHKdDdnldqlqkO0gAune9EH7oqICD1hP7c1duNZwvNnvyGa7SyqamIpNXmSYv303FEVAXzPsb9MzCChG16gzevQtbIX4Qt7vFOsHNSCikSCD/s6DMa0Koryiu7Yju5mW9UUnjVM+a1P80SOiK7p2UBQPFVKRrUtr0htV3U6a2rdP51Vzm2UCjChTUa4q7L3m4C7oB9aSvUsNTk+PmuJlAer4oOd7FsNPqD1Or3lRKAmgxbTX4xTaOkwibK0t2eYkh/VTUPMQ9wDwpa4hZLiEq9qSew3McCwsl70k4H0H4F/VwV2sSCXqZu274YmNDT5Hl3 hanzhichao@hanzhichao01", "title": "test3", "verified": true, "created_at": "2018-09-14T09:54:51Z", "read_only": false } 

Web Service

Web Service 是一種跨平臺(Java對象,Python也能夠調用)RPC(遠程方法調用)解決方案。
基於SOAP協議,使用XML這種跨平臺語言傳輸對遠程方法的調用信息及返回結果,並提供WSDL接口描述服務

  • SOAP:簡單面向對象協議, 基於XML語言,使用HTTP協議傳輸
  • XML: 可擴展標記語言,同JSON同樣是一種跨平臺語言
  • WSDL: Web Service服務描述語言,提供遠程對象的調用描述信息(相似於接口文檔,XML格式)

SOAP格式

SOAP協議基於XML語言, SOAP消息體首先必須有個信封(Enelope),信封中能夠有信息頭(Header)和信息體(Body),其中Body中還能夠包含錯誤信息(Fault)
基本格式以下:

<!-- 信封固定格式 指定命名空間爲soapenv --> <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2001/12/soap-envelope" soapenv:encodingStyle="http://www.w3.org/2001/12/soap-encoding"> <soapenv:Header> <!--信息頭 可選,可寫成但標籤--> ...... </soapenv:Header> <soapenv:Body> <!--信息體 實際調用內容--> ...... </soapenv:Body> </soap:Envelope> 

SOAP詳細教程:http://www.runoob.com/soap/soap-header.html

使用SoupUI
示例接口: http://115.28.108.130:4000/?wsdl
因爲Postman等不具有將wsdl接口信息解析成對象描述的功能,咱們使用另外一個SOAP接口專用的測試工具SoupUI

SoupUI下載地址: http://www.wmzhe.com/soft-32815.html

  1. 新建項目


    File -> 新建SOAP項目
填入項目名,WSDL地址,點擊OK
保存後自動解析出全部方法(接口)信息
  1. 發送接口
填寫參數處
填寫完參數,點擊發送按鈕,查看響應結果

使用Fiddler抓包,查看raw格式:

POST http://115.28.108.130:4000/ HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: "addUser"
Content-Length: 370
Host: 115.28.108.130:4000
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:user="UserService"> <soapenv:Header/> <soapenv:Body> <user:addUser> <!--Optional:--> <user:name>范冰冰</user:name> <!--Optional:--> <user:password>123456</user:password> </user:addUser> </soapenv:Body> </soapenv:Envelope> 

使用Postman發送SOAP接口

Postman發送SOAP接口

text/xml 和 application/xml的區別: 當你<?xml version='1.0' encoding='UTF-8'>指定編碼的時候,使用application/xml會安裝xml指定的編碼傳輸,而使用text/html會默認使用us-ascii編碼編碼傳輸數據

使用Python操做Web service接口

pip install suds-jurko

from suds.client import Client service = Client("http://115.28.108.130:4000/?wsdl").service # 獲取遠端服務對象 result = service.addUser("范冰冰", "123456") # 向本地方法同樣調用 print(result) # 輸出 用戶已存在 

使用requests庫發送

import requests

url = 'http://115.28.108.130:4000/'

data = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:user="UserService"> <soapenv:Header/> <soapenv:Body> <user:addUser> <!--Optional:--> <user:name>張三</user:name> <!--Optional:--> <user:password>123456</user:password> </user:addUser> </soapenv:Body> </soapenv:Envelope> '''.encode('utf-8') res = requests.post(url=url,data=data) print(res.text) 

結果:

<?xml version='1.0' encoding='UTF-8'?> <soap11env:Envelope xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tns="UserService"><soap11env:Body><tns:addUserResponse><tns:addUserResult>用戶已存在</tns:addUserResult></tns:addUserResponse></soap11env:Body></soap11env:Envelope> 

XML解析

XML: 可擴展標記語言,使用<tag></tag>標籤,多級樹狀結構,多用來存儲和傳輸數據,如:

<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore> 
  • 根元素(根節點),父元素,子元素,同級元素:bookstore爲根元素,book是title的父元素,title是book的子元素,title和author是同級元素
  • 標籤,屬性,文本:bookstore boot title等爲標籤(元素節點),boot中category="COOKING" category爲屬性,COOKING爲屬性值,<title></title>之間的Everyday Italian爲文本

Python解析XML

  1. 加載元素樹(ElementTree)獲得根節點
  2. 從根節點使用xpath查找其餘節點
from xml.etree import ElementTree
d = '''<bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore> ''' root = ElementTree.fromstring(d) # 加載元素樹(ElementTree)獲得根節點 print(root.find(".")) # 選擇當前節點 print(root.find("book")) # 選擇標籤爲book的子節點 print(root.find("book[2]")) # 選擇標籤爲book的第三個子節點 print(root.find("book[@category='COOKING']")) # 選擇標籤爲book切標籤屬性爲category="COOKING" print(root.find("./book/[title='Harry Potter']")) # 選擇標籤爲book的節點中包含子標籤title 切title的文本內容爲Harry Potter 

結果:

<Element 'bookstore' at 0x000002406B666688> <Element 'book' at 0x000002406B6666D8> <Element 'book' at 0x000002406B8600E8> <Element 'book' at 0x000002406B6666D8> <Element 'book' at 0x000002406B8600E8> 

find()返回的是節點對象,能夠經過.tag獲取標籤名,.attrib獲取屬性字典,.text獲取文本

XPath選擇器

  • 路徑: 按路徑選擇
  • 標籤名: 選定全部該名的標籤
  • *: 選定全部元素
  • . : 選擇當前節點
  • ..: 選擇上級節點
  • //: 選擇當前元素下全部級別的元素
  • [@屬性名]:選擇全部具備當前屬性的元素
  • [@屬性名=屬性值]: 選擇屬性=屬性值的元素
  • [子標籤名]:選擇具備當前子標籤的元素
  • [子標籤名='文本']: 選擇子標籤文本的元素

經常使用的三種定位元素方法

  1. 從根節點按路徑選擇: root.find("./book[3]/title")
  2. 按屬性並結合相對路徑選擇: root.find(book[@category='WEB']/title)
  3. 按所包含的獨特子標籤選擇: root.find(book[title='Harry Potter']/title)

Mock Server

Mock 即模擬,就是在測試過程當中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來建立以便測試的測試方法,其最大的優點就是降級先後端耦合度,使前端工程師能夠不依賴後端返回數據,先開發前端樣式以及邏輯處理
簡單來講: Mock是用瞭解決依賴問題的,將複雜的/不穩定的/還未創建的依賴對象用一個簡單的假對象來代替

Mock Server 即Mock接口服務器,能夠經過配置快速Mock出新的接口
Mock Server的使用範圍

  • 先後端分離項目
  • 所測接口依賴第三方系統(還未具有)
  • 所測接口依賴複雜或依賴的接口不穩定,並不做爲主要驗證對象

同時在接口還未開發好時,提供Mock接口(假接口)會比只有接口文檔更直觀,並能有效減小溝通成本和一些文檔理解bug

Postman的Mock Server功能

New -> Mock Server
添加接口及返回值
新建Mock環境
測試Mock接口

Postman還能夠基於Collection創建Mock Server,這裏再也不詳述

Python+Flask本身搭建Mock接口
使用Flask包咱們能夠快速搭建Mock接口

pip install flask

from flask import Flask, request, jsonify, abort import random app = Flask(__name__) # 實例化一個Flask對象 @app.route("/api/user/reg/", methods=["POST"]) def reg(): if not request.json or not 'name' in request.json or not 'password' in request.json: abort(404) res = [ { "code": "100000", "msg": "成功", "data": { "name": "李六", "password": "e10adc3949ba59abbe56e057f20f883e" } }, { "code": "100001", "msg": "失敗,用戶已存在", "data": { "name": "李六", "password": "e10adc3949ba59abbe56e057f20f883e" } }, { "code": "100002", "msg": "失敗,添加用戶失敗", "data": { "name": "李六", "password": "e10adc3949ba59abbe56e057f20f883e" } } ] return jsonify(random.choice(res)) if __name__ == '__main__': app.run() 
使用Mock接口
相關文章
相關標籤/搜索