看完這篇博客,我保證你確定會作接口測試了。

最近給公司的新員工培訓web api接口測試,發現這一塊的內部需求還比較大,不只僅是新員工,包括一些常常寫接口測試老員工,對接口也是似懂非懂的,因此我絕對有必要寫一篇博客來普及下。css

在咱們公司內部,通常使用ruby或者python語言來作接口測試,這篇文件主要是講解使用python語言來作接口測試。html

若是要作接口測試,其實只要會抓包會組裝http請求頭和請求體會檢查http響應頭和響應體,就能夠能夠,因此咱們須要須要掌握下面這些知識!!!另外還須要掌握一些經常使用的測試框架,好比unittest和pytest等python

一、python語言requests庫web

二、http協議基本知識,包括請求頭,響應頭、請求體、響應體數據庫

三、session-cookie(若是你們對session和cookies不熟悉,能夠看我以前寫 的博客)json

https://www.cnblogs.com/bainianminguo/p/9147418.html後端

https://www.cnblogs.com/bainianminguo/p/8850043.htmlapi

四、fiddler抓包工具瀏覽器

五、測試框架,這裏不會講,你們有興趣能夠看下我以前寫的博客,介紹unittest測試框架ruby

https://www.cnblogs.com/bainianminguo/p/11706244.html

https://www.cnblogs.com/bainianminguo/p/11616526.html

 

下面進入正題,聽我娓娓道來。

1、http協議

一、簡介

web api接口大都是基於http協議的,因此要進行接口測試,首先要了解HTTP協議的基礎知識。

HTTP協議全稱是超文本傳輸協議。因爲HTTP最初是用來在瀏覽器和網站服務器之間傳輸超文本的(網頁,視頻,圖片等)信息的。因爲HTTP簡潔易用,後來,不只僅是瀏覽器和服務器之間使用它,服務器和服務器之間,手機app和服務器之間,都普遍的採用,成了一個軟件系統間通訊的首選協議之一。

HTTP協議有好幾個版本,包括0.九、1.0、1.一、1.2,當前最普遍使用的是HTTP/1.1版本

HTTP協議最大的特色是通信雙方分爲客戶端和服務端。

因爲目前HTTP是基於TCP協議,因此要進行通信,客戶端必須先河服務端建立TCP鏈接。並且HTTP雙方的信息交互,必需要這樣一種形式

a、客戶端先發送http請求(request)給服務器

b、而後服務器發送http響應(response)給客戶端

c、特別要注意,在http協議中,服務端是不能主動發消息給客戶端的

流程圖以下

 

 

 

http1.1版本先建立TCP鏈接,而後在這個鏈接內能夠進行屢次交互信息,這裏注意,是客戶端主動給服務端發請求的

 

2、http請求

下面是http的get請求和http的post請求的示例

GET /mgr/login HTTP/1.1
Host: 192.168.3.1
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate, sdch

  

POST /api/test HTTP/1.1
Host:192.168.3.1
Origin:http://192.168.3.1
Referer:http://192.168.3.1/html/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type:application/json;charset=UTF-8
Content-Length:214
Accept-Language:zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Encoding:gzip, deflate

{"csrf":{"csrf_param":"35iUJau6mdmmJeIg0N8W80OmoMK8A2Kr","csrf_token":"KfKSfpH0hnsSc0uQyX6ZUB8i8KRFSZ0C"},"data":{"username":"admin","firstnonce":"c7eb46830667147fc62838e7ba9a0c09187d28bafa45b133897efa9d4e46a880"}}

  

一個http請求消息由下面幾個部分組成

a、請求行 request line

是http的第一行的內容。表示要操做什麼資源,使用的http協議的版本是什麼,裏面包含了三部分消息。請求的方法、操做資源的地址、協議的版本號

 

b、請求方法

Get請求

從服務器上獲取資源信息,這是一種最多見的請求

好比要從服務器獲取網頁資源,獲取圖片資源,獲取用戶信息數據等

 

Post請求

添加資源信息到服務器進行處理,例如要添加用戶信息,上傳圖片數據到服務器等,具體的數據信息,一般在HTTP請求的消息體中,這個後面會講

 

 Put請求

請求服務器更新資源信息

好比要更新用戶、姓名地址等等

具體的更新的數據信息,一般在HTTP的消息體中,後面會講

 

Delete請求

請求服務器刪除資源信息

好比要刪除某個用戶,某個資源等等

HTT片協議還有許多其餘的方法,好比PATCH,HEAD等,不是特別經常使用,暫且不講

 

c、資源地址

 

 

 

d、請求頭

 

 

 

這裏業務你們有個疑問,個人http請求是創建在tcp鏈接的基礎上的,爲何這裏還要傳遞一個host呢?由於咱們知道ip地址了,可是這個ip地址上可能有多個網站,因此這裏要指定咱們要訪問的具體是哪一個網站

請求體的http請求下面的內容,裏面存放一些信息。

好比請求發送的服務端的域名是什麼,但願接受的響應消息使用語言,請求消息體的長度等等;

一般請求頭有好多個,一個請求頭佔據一行

單個請求頭的格式是:名字:值

 

e、請求體

請求的url,請求頭中可存放一些數據信息,可是有些數據信息,每每需求存放在消息體中國;特別是post,put的請求,添加,修改的數據信息一般都是存放在請求消息體中的;

若是HTTP請求有消息體,協議規定,須要在消息頭和消息體之間插入一個空行,隔開他們;

請求消息體中保存了要提交個服務端的數據信息

好比:客戶端要上傳一個文件給服務器,就能夠經過http請求發送文件數據給服務端;

文件的數據就應該在請求的消息體中

請求的消息體一般是某種格式的字符串,常見的有三種,可是最經常使用的仍是json格式

Json

Xml

www-form-urlencoded

後面會有詳細的描述

 

request payload就是一個請求體,下面這個格式就是Json格式的消息體

 

 

 

請求體中不只僅能夠存放字符串,還能夠放二進制信息,好比如下視頻、文本之類的,用於咱們上傳文件的場景,不過一般接口測試不會涉及二進制信息,都是字符串信息,後面我會專門寫一篇博客來介紹如何上傳文件

 

二、http響應

響應的消息咱們重點關注狀態碼

a、2xx

一般表示請求消息沒有問題,並且服務器也正確處理了

b、3xx

這是重定向響應,常見的是是30一、302,表示客戶端的這個請求的url地址已經改變了,須要客戶端重啓發起一個請求到另一個url

c、400

表示客戶端請求不符合接口要求,好比格式徹底錯誤

d、401

表示客戶端須要先認證才能發送請求

e、403

表示客戶端美譽哦權限要求服務器處理這樣的請求,好比普通用戶的沒有管理員的權限

f、404

表示客戶端方法的url不存在

g、5xx

表示服務端在處理請求中,發送了未知錯誤,一般是服務端的代碼設計的問題,或者服務端系統出了故障了

 

有了以上的基礎,咱們就能夠作web的接口測試了

2、接口測試

一、什麼是接口測試

咱們一般說的接口測試,其實就是對軟件系統的消息交互接口的參數,消息交互接口是軟件系統和其餘軟件系統交互的那部分,好比,你正在用瀏覽器使用一個網站,瀏覽器和後端服務器之間就是消息交互的;在好比,你手機上使用美團訂餐,美團app和美團服務器之間,也是消息交互的,當你提交訂單,使用功能微信支付的時候,美團服務器和微信服務器之間也是經過消息交互的

 

 

 

 

接口測試就是

依據接口規範,寫出測試用例

使用軟件工具,直接經過消息接口對被測系統進行消息收發

驗證被測系統行爲是否正確

 

目前軟件系統之間的消息接口大部分是基於HTTP協議收發的

HTTP協議的特色是,客戶端發出一個HTTP請求給服務端,服務端就返回一個HTTP相應,好像API程序調用;

全部接口測試一般又被稱爲API接口測試或者WEB API接口測試

 

API接口傳遞數據信息是經過HTTP協議進行收發的,網站獲取網頁,圖片,css等資源,也是經過HTTP協議進行收發的

那麼這二者有什麼區別呢?爲何獲取網頁,圖片這些HTTP消息不叫作API接口消息呢?

網頁,圖片,css這些資源都是靜態資源,就是一個一個文件存儲在服務器中,獲取這些消息,服務端直接讀取文件,返回給客戶端便可,無需特別的數據處理

 

而API接口請求消息,一般都須要服務端程序進行一番處理,好比對請求的權限檢查,從數據庫中讀出數據,進行消息過濾和格式轉換,最後在HTTP響應中返回給客戶端

接口測試須要工具和被測系統之間進行消息的收發,這個工具能夠是別人開發的,也能夠本身開發,基於HTTP的接口測試工具備Postman,Jmeter等

 

二、fiddler工具

這裏咱們使用python語言中的requests庫和fiddler抓包工具

Fiddler:代理式抓包

你們必定會反問,個人瀏覽器就是能夠抓包了,爲何還要安裝fiddler,畫蛇添足?

其實否則,由於咱們是用python的requests庫去作接口測試,瀏覽器是抓不到咱們發的請求的,因此須要安裝fiddler來抓包,確保咱們發送的http請求是正確的

 

fiddler啓動後,會啓動一個代理服務器,監聽在8888端口上,http客戶端須要設置fiddler做爲代理,把http請求消息發送給fiddler,fiddler轉發http消息給服務端,服務端返回消息也是先返回給fiddler。再由fidddler轉發給客戶端

以下圖所示

 

 

  

fiddler安裝後,會默認配置操做系統級別的代理,能夠經過下面的方式查看

 

 

 

安裝fiddler須要配置一個過濾項,由於默認fiddler是做爲一個系統代理,因此fiddler抓到包會不少,因此須要配置一個過濾項

 

 

 

 

一樣,這裏的配置是支持通配符的

 

 

 

抓包

 

 

 

 

查看原始的請求消息

 

 

 

 

咱們能夠在python代碼裏配置代理,而後經過fiddler抓包來判斷咱們發的包是否準確,這裏須要配置http和https協議的代理

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "htt://www.baidu.com",
    proxies = proxies
)

  

咱們能夠經過fiddler進行抓包

 

 

 

fiddler若是 要配置手機抓包代理,須要保證安裝fiddler和手機在同一個局域網中

 

 

 

在手機的無線網絡處配置代理,代理指向運行fiddler的電腦的ip便可,端口是8888

 

三、requests庫的請求

a、構建請求的url參數,這個通常在get請求使用較多

什麼是url參數

好比

https://www.baidu.com/s?wd=iphone&res_spt=1

  

問號後面的部分wd=iphone&res_spt=1就是url參數,每一個參數之間就用&隔開的。

上面的例子中有兩個參數wd和res_spt,他們的值分別iphone和1

url參數參數的格式,有個術語叫urlencoded格式

 

使用requests發送HTTP請求,url裏面的參數,一般能夠直接在url裏面,好比

 

 

可是有的時候,咱們的url中參數裏面有特殊字符,好比參數中的值包含了一個&這個符號或者參數不少的話,咱們能夠採用下面的方法,構建一個字典,而後把這個字典傳遞給params參數 

也能夠用下面的方式傳遞url參數

res = requests.get(
    url = "http://www.baidu.com/",
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

b、構建請求消息頭

有的時候,咱們須要自定義一些http的消息頭

每一個消息頭也就是一種鍵值對的格式存放數據,在requests,只須要把抓包中的請求頭信息放在一個字典中,而後傳遞headers便可

res = requests.get(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch"
        },
    params = {
        "wd":"iphone",
        "res_spt":"1"
    },
    proxies = proxies
)

  

 

c、構建請求的消息體

當咱們進行api接口測試的時候,根據接口規範,構建的http請求,一般須要構建消息體

http的消息體就是一串字節,裏面包含了一些信息,這些信息多是文本,好比html網頁做爲消息體,也多是視頻,音頻信息

消息體可能很短,只有一個字節,好比字符a,也可能很長,有幾百個字節

最多見的消息體格式固然是表示網頁內容的html

當時在web api接口測試中,常見的HTTP消息體的格式有三種,urlencoded,json,xml

注意:消息體採用什麼格式,是由開發人員設計決定的,開發人員也能夠自定義格式,可是咱們一般不會自定義的

 

xml格式

前面時候了,消息體就是存放信息的地方,信息的格式徹底取決於設計者的需求,若是設計者決定使用xml格式傳輸一段信息,用requests庫,只須要這樣就能夠了

 

playload = """
    <?xml version="1.0"?>
    <methodCall>
        <methodName>examples.getStateName</methodName>
        <params>
            <param>
                <value><i4>41</i4></value>
            </param>
        </params>
    </methodCall>"""

res2 = requests.post(
    url = "http://www.baidu.com/",
    headers = {
        "Host": "192.168.3.1",
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "text/xml"
        },
    data=playload.encode("utf-8"),
    proxies = proxies
)

  

因爲消息體都是字節串,咱們直接把字符串使用utf-8解碼,而後傳遞給data參數便可,這裏須要注意,須要設置Content-type=text/xml

 

 

 

 

使用data參數,存儲消息體的數據,若是傳遞的是一個字符串,在http請求中,須要編碼爲字節碼,默認的編碼格式latin-1,這種編碼格式是不支持中文的;一般咱們使用utf-8的編碼格式

經過fiddler抓包

 

 

 

查看請求的原始信息

 

 

 

 

 

 

Urlencoded格式

這種格式的消息體就是一個key-value鍵值對的格式存放數據,以下所示

key1=value1&key2=value2

 

Requests發送這樣的數據,固然能夠直接把這種格式的字符串傳入到data參數裏;可是這樣寫的話,若是參數自己就有特殊字符,好比等號,就會有歧義

咱們還有更方便的方法,只須要將這些鍵值對的數據構建一個字典,以下

playload = {
    "key1":"value1",
    "key2":"value2"
}

res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"
        },
    data=playload,
    proxies = proxies
)

  

這裏須要注意下面2個地方

 

 

 

 

經過fiddler抓包

先看請求頭

 

 

 

這裏明顯能夠看到,請求頭和請求體中間有一個空行

 

 

 

看下請求體中的數據

 

 

 

 

Json格式的消息體

Json字符串一概用雙引號,不能用單引號

Json字符串最後一個元素的後面不能加逗號

 

其實咱們要把數據放到消息體中,最終的數據都是字節串,也就是把str.encode()

json格式當前被web api接口普遍採用

json是一種表示數據的語法格式,他和python表示數據的語法很是像

json格式有兩種方式構建消息體

方式1

playload = {"title": "test", "sub": [1, 2, 3]}
res2 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    json=playload,
    proxies = proxies
)

  

注意下面這裏

 

 

 

方式2

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)

  

注意下面這裏

 

 

四、requests庫的響應

a、檢查HTTP響應狀態碼

要檢查HTTP響應的狀態碼,直接經過response對象的status_code屬性獲取

import json
playload = {"title": "test", "sub": [1, 2, 3]}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(res3.status_code)

  

運行結果發現返回的結果狀態碼就是200

 

 

 

 

若是故意寫一個不存在的地址

import requests

proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = requests.get(
    url = "http://192.168.3.1/html/index4.html",
    proxies = proxies
)

print(res.status_code)

  

運行結果發現返回的狀態碼就是404

 

 

 

 

b、檢查響應的消息頭

要檢查HTTP響應的消息頭,直接經過response對象的header屬性獲取

import json
import requests
import pprint
playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
res3 = requests.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)


print(pprint.pprint(dict(res3.headers)))

  

結果以下

 

 

 

 

 

 

 

c、檢查響應消息體的文本內容

前面咱們已經說過,要獲取響應的消息體的文本內容,直接經過response對象的text屬性便可獲取

import requests
import pprint
#
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}
#
res = requests.get(
    url = "http://mirrors.sohu.com",
    proxies = proxies
)
#
#
# print(res.text)
print(pprint.pprint(dict(res.headers)))
print(res.encoding)

  

  

響應體其實也是字節串,可是咱們調用text方法沒有設置解碼格式,他是怎麼解碼?他是根據響應頭的contend-type來決定解碼格式,有的時候會指定,可是大部分不會指定

咱們

 

 

 

 

咱們能夠看到咱們打印的解碼格式,和content-Type中是同樣的

 

 

 

 

若是有的時候中文解碼出來是亂碼,咱們能夠手動指定解碼格式

 

 

 

 

 

若是咱們想打印響應體的字節串可使用content方法

 

 

 

 

 

五、session

a、原理

咱們來思考一個問題,一個網站,好比一個購物網站,服務成千上萬的的客戶,那麼多客戶同時訪問網站,挑選物品,購物估算,都是經過hTTP請求來訪問網站的,這個網站的服務端怎麼區分每一個HTTP請求呢?網站的服務端是怎麼實現的?

一種最多見的方式就是:經過Session+cookies機制

session翻譯成中文就是會話的意思

session大致的原理以下面2個圖

 

 

 

 

 

 

 

 

 

http協議規定了,網站的服務端放HTTP響應的消息頭set-Cookies裏面的數據,叫作cookies數據,瀏覽器客戶端必需要保存下來。並且後續訪問該網站,必須在http的請求頭Cookies中攜帶保存的全部的cookie數據

用戶使用客戶端登錄服務端,服務端進行驗證,好比驗證用戶名和密碼,驗證經過後,服務端系統高就會爲此次登錄建立一個seesion,同時建立一個惟一的sessionID。標誌這個session。而後,服務端經過HTTP響應,把sessionID告訴客戶端,客戶端在後面的HTTP請求的消息頭,都要包含這個sessionID。這樣服務端就會知道,這個供求對應哪一個session,從而知道此次的請求對應哪一個用戶;

 

 

 

 

從上圖能夠看出,服務端是經過HTTP的響應頭set-cookies把產生的sessionID告訴客戶端。

 

 

 

 

客戶端的後續請求,是經過HTTP請求的請求頭Cookies告訴服務端他所持有的sessionid的

 

b、request庫支持session的

request處理session-cookies

咱們在python代碼中若是接收到服務器的http響應,其餘set-cookies的數據怎麼保存呢?後續怎麼樣把請求消息頭中cookies中呢?

前面學過HTTP響應中如何獲取響應頭,構建請求怎麼設置請求頭,徹底能夠處理。

可是requests庫爲咱們這個處理

requests庫給咱們提供了一個session類。經過這個類,無需咱們操心cookies和session這個事情。reqeusts庫會自動幫咱們保存服務端發揮的cookies數據,HTTP請求自動在消息頭中放入cookies數據

以下所示

import requests
import json
session = requests.session()

playload = {"title": "test", "sub": [1, 2, 3]}
proxies = {
    "http":"127.0.0.1:8888",
    "http1": "127.0.0.1:8888"
}

res = session.post(
    url = "http://www.example.com",
    headers = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",
        "Accept-Encoding":"gzip, deflate, sdch",
        "Content-Type": "application/json;charset=utf-8"
        },
    data = json.dumps(playload,ensure_ascii=False).encode("utf-8"),
    proxies = proxies
)



res = session.get()
相關文章
相關標籤/搜索