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系統接口,這樣hr系統的接口會返回給我用戶的一些更加具體的信息。這裏的輸入是用戶名,輸出是用戶的詳細信息。
爲何要作接口測試
既然是接口獲取和操做資源的方式,而大部分系統和產品中,資源通常都是產品的核心,好比微信核心資源就是通信錄關係鏈和聊天記錄等,所以資源是必測的。
另外接口中大部分的內容是數據,經過數據的對比咱們能推測到系統和產品的邏輯,測接口就是測邏輯。
最後接口中的返回相對單純,不像web頁面,html代碼中有太多ui的東西,ui最不穩定,變化太快,接口相對穩定一點點,可是裏面的干擾信息更少,斷言相對容易不少。
接口測試用例怎麼寫
仍是3a原則,這個我之前的回答裏有。
接口測試筆試題
有哪些常見的接口
常見的接口測試工具
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://www.v2ex.com/api/nodes/show.json?name=python,這個http的get請求給服務器以後,服務器應該返回相應的資源,那麼這時候就須要探討一下
如何查看接口的返回
咱們如今已經知道了這個接口的狀況了,如何查看接口的返回呢?
咱們可使用一些輔助工具幫助咱們進行接口的調用,查看接口返回,最簡單的跨平臺調試工具推薦使用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中展現出來。
服務器響應
上圖就是服務器的響應詳情,這裏包含了一些重要信息
json字符串
有基礎的同窗能夠看出來,響應的主體是json格式的字符串,那麼什麼是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
2018年10月7日 星期日
12:09
3A原則本來是單元測試用例編寫時應該遵循的基本原則,不過咱們能夠擴展到接口的自動化測試用例編寫中來。
咱們首先看一下3A原則在每一層自動化測試中的具體應用。
單元測試用例
給一個例子(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原則也適用於這種測試用例的編寫
舉個例子(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 and act
打開chrome瀏覽器並跳轉至http://localhost/wordpress/wp-login.php
在用戶名文本框中輸入admin
在密碼文本框中輸入admin
點擊登錄按鈕
# assert
瀏覽器跳轉到http://localhost/wordpress/wp-admin/
右上角出現「你好,admin」字樣
總結
總之對於接口的自動化測試用例說來,遵循3A原則就意味着
2018年10月7日 星期日
12:10
在咱們真正的編寫測試用例以前,咱們須要瞭解一下測試框架。
unittest是python自帶的單元測試框架,儘管其主要是爲單元測試服務的,但咱們也能夠用它來作接口的自動化測試。
unittest框架爲咱們編寫用例提供了以下的能力
簡單的例子
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的話須要記住下面的幾點
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。
安裝
快速開始
劃重點
英文很差的同窗能夠參考中文文檔的相關章節。
2018年10月7日 星期日
12:10
前面鋪墊了不少的基礎知識,掌握基礎知識是作基於http接口自動化測試的前提,不建議直接跳過。
前提條件
學習本節須要有一些前提條件
用例描述
在認識測試對象這一節裏有過描述。
得到指定節點的名字,簡介,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
總結
2018年10月7日 星期日
12:11
使用場景
前端客戶端團隊和後端服務端團隊每每節奏是不一致的。前端不少狀況下須要等待後臺的api開發完成後才能進行開發聯調和測試,這種先後端不對稱就形成了先後端團隊節奏不一致,從而形成整個項目/產品交付/發佈延期。
有一種解決方案的思路是先後端先約定好後端提供的api接口的細節,前端人員自行先模擬出這些後端的實現,固然這些實現是假的,不過前端能夠去調用這些假的實現,並且能拿到返回,這樣一來前端就不須要等待後端開發完成纔開始工做了。
可是這樣仍是會有問題,前端實現的假的api沒辦法迅速反映出後端的變化。簡單來講就是後端可能在約定好的api接口上進行了些許修改,而沒有知會前端人員,這樣前端的假的api實現並無相應更新,在正式聯調時就會出現問題。
像這種假的api實現,無論是前端實現的仍是後端去實現的,咱們能夠稱之爲mock server。
契約測試
因爲先後端每每有一些信息不對稱,致使約定的api可能在先後端都會發生變化,因此保證先後端的一致性就成了一個挑戰。
這時候有人提出了契約測試,大體思想是先後端共用一份契約,約定了api的細節,先後端的任何變化都須要先修改契約,而後經過契約去通知先後端團隊,統一更新實現。這也是契約精神的表現。
若是爲契約測試設置一種測試工具的話,我會規劃下面一些特性
2018年10月7日 星期日
12:11
flask
flask是python實現的簡單的web框架,與django互補。
flask教程
如何理解flask
最簡單的例子
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就行了