在咱們進行單元測試的過程當中,若是咱們須要對一些HTTP接口進行相關的業務測試,那麼咱們就須要來模擬HTTP請求的發送與響應,不然咱們就沒法完成測試的閉環。javascript
目前,有許許多多的測試框架都提供了模擬HTTP請求相關的一些流程功能,咱們在這邊文章中將會講到的,就是咱們在上一篇關於單元測試的博客提升代碼質量——使用Jest和Sinon給已有的代碼添加單元測試中提到的Sinon中引用的HTTP模擬框架nise。java
本文的目標是讓讀者可以經過這篇文章,知道一個成熟的測試框架是如何來模擬一個HTTP的實現,而且與業務代碼進行結合,輔助進行測試。本文內容相對較爲簡單,基本沒有難度,做爲一個知識面擴充建議讀者快速略讀。git
經過本文,你能夠了解如下內容:github
fake XHR and Server.json
nise在Github上面的介紹很簡單,雖然只有四個單詞,可是卻很精確的說明了這個庫的含義——構造一個模擬的XHR和Server對象,用來替換原生的對象用來知足測試需求。瀏覽器
它是Sinon.js的一部分,用來處理HTTP相關測試問題。app
該庫提供了替換原生的XHR對象和Server相關的接口,可是咱們在本文中只介紹關於XHR部分,也就是瀏覽器中的XHR對象的替換。該部分位於倉庫中/lib/fake-xhr/index.js
中,下文中提到的nise若是沒有特別註明,均表示nise中的XHR。框架
想要了解nise的設計思路,咱們就須要先看下nise的使用方法。async
目前,nise提供瞭如下三個API接口:ide
module.exports = {
xhr: sinonXhr, // 用來存儲原來的XHR對象和一些環境判斷屬性
FakeXMLHttpRequest: FakeXMLHttpRequest, // XHR對象構造函數
useFakeXMLHttpRequest: useFakeXMLHttpRequest //調用後,使用fake XHR對象替換全局,並返回一個帶有restore方法的fake XHR對象構造函數
};
複製代碼
咱們在使用時,只需調用userFakeXMLHttpRequest
方法,便可將原生的XHR對象替換成nise提供的XHR對象。在測試完成後,咱們再調用返回的restore
方法,這樣咱們就恢復了原生的XHR對象。
返回的模擬HXR對象還有部分API接口能夠調用,這部分咱們將在下一節——nise結構中進行介紹。
// 構造函數,用來存儲請求相關的數據如請求狀態、請求頭等
function FakeXMLHttpRequest(config) {
EventTargetHandler.call(this);
this.readyState = FakeXMLHttpRequest.UNSENT; // 原生屬性,用來標識請求狀態
this.requestHeaders = {}; // 記錄請求headers屬性
this.requestBody = null; // 記錄請求body屬性
this.status = 0;
this.statusText = "";
this.upload = new EventTargetHandler(); // 上傳事件屬性
this.responseType = ""; // 響應類型屬性
this.response = ""; // 響應內容屬性
this.logError = configureLogError(config);
if (sinonXhr.supportsTimeout) {
this.timeout = 0;
}
if (sinonXhr.supportsCORS) {
this.withCredentials = false;
}
if (typeof FakeXMLHttpRequest.onCreate === "function") {
FakeXMLHttpRequest.onCreate(this);
}
}
FakeXMLHttpRequest.useFilters = false;
FakeXMLHttpRequest.addFilter = function addFilter(fn) {} // 增長過濾函數
FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {} // 將經常使用事件如open、send等XHR的方法綁定到模擬的XHR對象上
FakeXMLHttpRequest.parseXML = function parseXML(text) {} // 解析XML
extend(FakeXMLHttpRequest.prototype, sinonEvent.EventTarget, {
open: function open(method, url, async, username, password) {} // XHR原生方法模擬
readyStateChange: function readyStateChange(state) {} // XHR原生方法模擬
setRequestHeader: function setRequestHeader(header, value) {} // 設置請求header並保存到requestHeaders屬性中
setStatus: function setStatus(status) {} // 設置status並保存到status屬性中
setResponseHeaders: function setResponseHeaders(headers) {} // 設置響應headers並跟隨callback一塊兒返回
send: function send(data) {} // XHR原生方法模擬
abort: function abort() {} // 終止HTTP請求
error: function () {} // XHR原生方法模擬
triggerTimeout: function triggerTimeout() {} // 觸發超時
getResponseHeader: function getResponseHeader(header) {} // 獲取響應header
getAllResponseHeaders: function getAllResponseHeaders() {} // 獲取所有的響應headers
setResponseBody: function setResponseBody(body) {} // 設置響應內容
respond: function respond(status, headers, body) {} // 觸發請求的callback函數
uploadProgress: function uploadProgress(progressEventRaw) {} // 上傳進度觸發事件
downloadProgress: function downloadProgress(progressEventRaw) {} // 下載進度觸發事件
uploadError: function uploadError(error) {} // 上傳失敗觸發事件
overrideMimeType: function overrideMimeType(type) {} // 覆蓋mineType
});
複製代碼
經過上面的源碼介紹咱們能夠知道:nise是經過徹底模擬一個模擬的XHR對象,而後再使用這個模擬的XHR對象來替換全局的XHR對象。
而咱們在進行HTTP相關測試時,參數是由咱們傳入的,所以不須要進行驗證。因此咱們最終須要驗證的實際上是callback中的處理邏輯和結果。所以,咱們能夠經過如下一個示例來看下它如何與業務代碼進行結合。這個示例是在上一篇博客中出現過的示例:
test('user', () => {
let callback = jest.fn();
HTTPCommon.deleteRemoteSession({
data: {},
success: callback
});
expect(requests.length).toBe(1);
requests[0].respond(200, {"Content-Type": 'application/json'}, 'hjava'); // 模擬返回值
expect(callback.mock.calls[0][0]).toBe('hjava');
});
複製代碼
經過respond
這個方法,fakeXMLHttpRequest對象觸發了callback函數,而且將指定數據傳遞到業務代碼中。所以,咱們可以經過callback相關的業務邏輯來判斷咱們的邏輯是否正常。
nise經過一個很是常規的方法——模擬一個XHR對象而且實現XHR對象的全部功能來完成針對HTTP請求進行記錄的功能。咱們再經過nise記錄的數據,組合其餘的單元測試框架來對業務代碼進行測試。
nise的源碼只有600餘行,並且很是簡單易懂。我將原有代碼folk一份並加上了部分註釋,有興趣的同窗能夠看看,具體地址見此處。