一篇文章瞭解_接口測試

1.爲何要作接口測試

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系統中判斷該人員是否存在,若是存在驗證用戶名和密碼,若是驗證經過就返回1個token,該token就是這我的員的通行證,經過token能夠登陸到bug管理系統中去;
  • 獲取人員信息的接口,返回該人員的職位:測試仍是開發,以及用戶名,暱稱等信息;

綜上:接口能夠理解成是不一樣系統或模塊之間資源交流方式;

接口測試其實是黑盒測試

做爲黑盒測試,基本的測試思路是經過輸入和輸出判斷被測系統或者對象的邏輯。

獲取人員的信息,我須要把人員的用戶名傳給hr系統接口,這樣hr系統的接口會返回給我用戶的一些更加具體的信息。這裏的輸入是用戶名,輸出是用戶的詳細信息。

爲何要作接口測試

既然是接口獲取和操做資源的方式,而大部分系統和產品中,資源通常都是產品的核心,好比微信核心資源就是通信錄關係鏈和聊天記錄等,所以資源是必測的。

另外接口中大部分的內容是數據,經過數據的對比咱們能推測到系統和產品的邏輯,測接口就是測邏輯。

最後接口中的返回相對單純,不像web頁面,html代碼中有太多ui的東西,ui最不穩定,變化太快,接口相對穩定一點點,可是裏面的干擾信息更少,斷言相對容易不少。

接口測試用例怎麼寫

仍是3a原則,這個我之前的回答裏有。

  • A: arrange 初始化測試數據,就是造數據,這裏的數據有咱們輸入的數據,也有目標接口所涉及的資源,好比hr系統中的用戶信息,咱們必須先有幾條人員的詳細信息才能去測獲取人員信息的接口(固然只是正常的流程,咱們有時候還須要清掉數據以便測試資源爲空的狀況);
  • A: act 調用接口,傳入輸入數據;
  • A: assert 斷言, 對返回的資源信息進行斷言,好比獲取用戶信息的接口返回了用戶信息以後,咱們要判斷返回的用戶是否是咱們想要的那個用戶,咱們獲取的是李雷的信息,接口若是返回韓梅梅,那麼接口的邏輯就是不對的;

接口測試筆試題

測試教程網接口測試筆試題

有哪些常見的接口

  • 攜程訂飛機票,飛機票的信息通常都是經過各大航空公司的接口拿到的;
  • 淘寶的物流信息,通常淘寶的物流信息都是經過各個物流公司的接口拿到的;
  • 第三方微博客戶端,我的用戶的微博等信息都是經過微博的接口拿到的;

常見的接口測試工具

  • postman: 推薦。基本功能免費。最簡單的基於http接口的調試和測試工具;
  • jmeter:後置處理器配合斷言基本上能夠知足接口測試需求,就是測試報告要作二次開發
  • 本身擼代碼:推薦。配合相似xunit測試框架,基本能夠知足一切需求;零基礎實現python接口自動化視頻教程,一塊兒擼代碼吧
  • soapui: 收費的;
  • insomnia:強力推薦。postman的弱化版,基本功能免費,重要的是工具代碼開源,能夠本身改;
  • paw: 強力推薦。mac上最強,淘寶買個受權好像就百把塊錢;

 

 

2.最簡單的接口長什麼樣

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協議,也就是更安全版本的http協議;
  • 請求的方法:http協議裏定義了一些請求的方法或者叫動詞,這些方法和動詞能夠進一步定義請求的目的,好比是獲取資源仍是建立資源等;上面的例子裏,請求方法是GET;
  • 請求參數:http協議裏規定了請求的時候能夠傳遞一些參數給服務端,這些參數能夠更加具體的描述資源,好比獲取多少個資源,這個資源的名字是什麼。上面的例子裏,咱們能夠傳遞name參數指定資源的名稱,好比獲取名字叫python的資源,這裏資源就是節點;
  • 鑑權:簡單來講,就是要不要登陸,很顯然,上面的接口是不須要登陸的

合起來,咱們應該能夠獲得這樣的信息:

當咱們發送:https://www.v2ex.com/api/nodes/show.json?name=python,這個http的get請求給服務器以後,服務器應該返回相應的資源,那麼這時候就須要探討一下

如何查看接口的返回

咱們如今已經知道了這個接口的狀況了,如何查看接口的返回呢?

咱們可使用一些輔助工具幫助咱們進行接口的調用,查看接口返回,最簡單的跨平臺調試工具推薦使用postman

 

 

3.入門級接口測試工具: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中展現出來。

服務器響應

上圖就是服務器的響應詳情,這裏包含了一些重要信息

  • 狀態碼: 200,表示響應是ok的
  • Body: 返回的主體
  • Headers: 能夠簡單的理解爲一些鍵值對,對請求的主體起到了補充的做用
  • Time: 響應時間
  • Size: 響應的大小

json字符串

有基礎的同窗能夠看出來,響應的主體是json格式的字符串,那麼什麼是json格式字符串呢?下一節咱們將詳細講解。

 

 

4.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

 

 

5.3A原則

2018年10月7日 星期日

12:09

 

3A原則本來是單元測試用例編寫時應該遵循的基本原則,不過咱們能夠擴展到接口的自動化測試用例編寫中來。

咱們首先看一下3A原則在每一層自動化測試中的具體應用。

單元測試用例

  • Arrange: 初始化測試對象或者準備測試數據
  • Act : 調用被測方法
  • Assert: 斷言

給一個例子(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原則也適用於這種測試用例的編寫

  • A: arrange 初始化測試數據,就是造數據,這裏的數據有咱們輸入的數據,也有目標接口所涉及的資源,好比hr系統中的用戶信息,咱們必須先有幾條人員的詳細信息才能去測獲取人員信息的接口(固然只是正常的流程,咱們有時候還須要清掉數據以便測試資源爲空的狀況);
  • A: act 調用接口,傳入輸入數據;
  • A: assert 斷言, 對返回的資源信息進行斷言,好比獲取用戶信息的接口返回了用戶信息以後,咱們要判斷返回的用戶是否是咱們想要的那個用戶,咱們獲取的是李雷的信息,接口若是返回韓梅梅,那麼接口的邏輯就是不對的;

舉個例子(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: 準備被測功能相關的測試數據,好比往系統裏錄入一批工單以便測試工單的分頁功能
  • Act : 調用被測的功能,實際上這就是咱們一直講的測試步驟
  • Assert: 斷言

舉個例子

# arrange and act
打開chrome瀏覽器並跳轉至http://localhost/wordpress/wp-login.php
在用戶名文本框中輸入admin
在密碼文本框中輸入admin
點擊登錄按鈕
# assert
瀏覽器跳轉到http://localhost/wordpress/wp-admin/
右上角出現「你好,admin」字樣

總結

總之對於接口的自動化測試用例說來,遵循3A原則就意味着

  • Arrange: 測試用例執行以前須要準備測試數據,包括須要輸入的數據及存量數據
  • Act: 經過不一樣的參數來調用接口,並拿到返回
  • Assert: 必須作斷言,不然用例就沒有任何意義了

 

 

6.unittest框架

2018年10月7日 星期日

12:10

在咱們真正的編寫測試用例以前,咱們須要瞭解一下測試框架。

unittest是python自帶的單元測試框架,儘管其主要是爲單元測試服務的,但咱們也能夠用它來作接口的自動化測試。

unittest框架爲咱們編寫用例提供了以下的能力

  • 定義用例的能力。unittest框架有一套固有套路,可讓咱們定義測試用例時更加簡單和統一
  • 斷言的能力。unittest框架提供了一系列的斷言
  • 各類執行策略。經過test suit或者擴展的方式,咱們能夠自定義用例執行的策略

簡單的例子

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的話須要記住下面的幾點

  • 導入unittest
  • 定義繼承自unittest.TestCase的測試類
  • 定義以test開頭的測試方法,這個方法就是測試用例,你能夠在一個類裏定義n個測試用例
  • 斷言
  • unittest.main()是執行測試用例最簡單的方式

 

 

 

7.requests庫

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。

安裝

官方文檔 中文文檔

快速開始

官方文檔 中文文檔

劃重點

英文很差的同窗能夠參考中文文檔的相關章節。

 

 

8.第一個用例

2018年10月7日 星期日

12:10

 

前面鋪墊了不少的基礎知識,掌握基礎知識是作基於http接口自動化測試的前提,不建議直接跳過。

前提條件

學習本節須要有一些前提條件

  • 安裝了postman
  • 安裝了python
  • 安裝了requests

用例描述

認識測試對象這一節裏有過描述。


得到指定節點的名字,簡介,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

總結

  • postman能夠幫助咱們完成50%左右的工做,好比調試接口,導出部分代碼等
  • 使用unittest重構用例能夠幫助咱們添加斷言,提供在命令行執行的能力,很容易跟ci工具進行集成

 

 

 

9.什麼是mock server

2018年10月7日 星期日

12:11

 

使用場景

前端客戶端團隊和後端服務端團隊每每節奏是不一致的。前端不少狀況下須要等待後臺的api開發完成後才能進行開發聯調和測試,這種先後端不對稱就形成了先後端團隊節奏不一致,從而形成整個項目/產品交付/發佈延期。

有一種解決方案的思路是先後端先約定好後端提供的api接口的細節,前端人員自行先模擬出這些後端的實現,固然這些實現是假的,不過前端能夠去調用這些假的實現,並且能拿到返回,這樣一來前端就不須要等待後端開發完成纔開始工做了。

可是這樣仍是會有問題,前端實現的假的api沒辦法迅速反映出後端的變化。簡單來講就是後端可能在約定好的api接口上進行了些許修改,而沒有知會前端人員,這樣前端的假的api實現並無相應更新,在正式聯調時就會出現問題。

像這種假的api實現,無論是前端實現的仍是後端去實現的,咱們能夠稱之爲mock server。

  • mock表示這個api返回的數據是假的,僅做爲測試用的
  • server表示須要啓動服務,說到底這是一個服務程序

契約測試

因爲先後端每每有一些信息不對稱,致使約定的api可能在先後端都會發生變化,因此保證先後端的一致性就成了一個挑戰。

這時候有人提出了契約測試,大體思想是先後端共用一份契約,約定了api的細節,先後端的任何變化都須要先修改契約,而後經過契約去通知先後端團隊,統一更新實現。這也是契約精神的表現。

若是爲契約測試設置一種測試工具的話,我會規劃下面一些特性

  • 契約的描述工具:也就是契約長什麼樣子,用什麼工具去定義才能讓先後端團隊秒懂
  • 經過契約自動生成mock server實現,這樣前端團隊就能夠拿來即用了,若是契約修改了,那麼前端團隊也很容易感知到
  • 經過契約自動生成接口測試用例,這樣經過持續運行這些接口測試用例,後端團隊就能夠第一時間發現契約的修改

 

 

 

10.使用flask實現mock server

2018年10月7日 星期日

12:11

 

flask

flask是python實現的簡單的web框架,與django互補。

flask教程

如何理解flask

  • 路由 -> /request/uri
  • handler -> 路由進來以後處理request並返回response的邏輯

最簡單的例子

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就行了

相關文章
相關標籤/搜索