
API優先設計:構建可擴展且靈活的軟件的現代方法
在安裝任何 Node 模塊之前,你應該確保你的根目錄中有一個 package.json 文件。如果沒有,你可以使用以下命令進行設置:npm init -y
。
讓我們首先在你的項目目錄中安裝 Jasmine:npm install jasmine –save-dev
完成后,您可以使用以下命令配置 Jasmine:node node_modules/jasmine/bin/jasmine.js init
這將創建一個 spec 文件夾,其中包含一些具有默認設置的配置文件。請務必記住,我們編寫的測試文件應以“spec.js”結尾
最后,我們需要在 package.json 文件中設置測試命令。打開此文件并向對象添加一個包含 Jasmine 模塊路徑的test
鍵。它應該如下所示:scripts
"scripts":{
"test":"jasmine"
}
讓我們確保所有設置都正確。在spec
名為my-first-spec.js
paste this 的文件夾中創建一個名為的文件:
describe('My Jasmine Setup', function () {
var a = true;
it('tests if the value of a is true', function () {
expect(a).toBe(true);
});
});
您可以通過運行我們在 package.json 中放入的測試腳本在終端中運行測試:npm run test
您的測試應該會通過!嘗試將值更改a
為 false,然后再次運行它,看看測試失敗時會是什么樣子。請注意,當出現問題時,它會向您提供描述性消息。
Jasmine 測試套件的另一個很酷的功能是“beforeEach”和“afterEach”函數。這允許您在每個“it”塊之前或之后執行某些操作。讓我們在每次測試之前創建一個新的 MockAPI 類實例。
以下腳本可以在 Jasmine 或 Jest 中運行:
const MockAPI= require('../MockAPI.js');
describe("Mock API",()=>{
let mockAPI;
let mockDatabase=
{
users:[
{
name:"Jack",
passwordHash:"dasdKDKDJSLASDLASDJSAasdsdc123",
posts:["I just bought some magic beans!"]
},
{
name:"Jill",
passwordHash:"dasdKDKDJSLASDLASDJSAasdsdc123"
posts:["Jack fell down!"]
},
]
};
beforeEach(()=>{
mockAPI= new MockAPI(mockDatabase)
})
it("returns a 400 bad request status if the request is invalid",()=>{
const mockApiCall=mockAPI.simulateAsyncCall({})
return mockApiCall.then(response=>{
expect(response.status).toBe(400)
})
})
describe("get requests",()=>{
const validRequest={method:'get',body:{user:"Jack"}};
const invalidRequest={method:'get',body:{user:"Tod"}};
it("returns a 404 status if a user is not found",()=>{
const mockApiCall=mockAPI.simulateAsyncCall(invalidRequest)
return mockApiCall.then(response=>{
expect(response.status).toBe(404)
})
});
it("returns a 200 status with a user's posts",()=>{
const mockApiCall=mockAPI.simulateAsyncCall(validRequest)
return mockApiCall.then(response=>{
expect(response.status).toBe(200)
expect(response.posts).toEqual(["I just bought some magic beans!"])
})
});
})
describe("post requests",()=>{
const validRequest={method:'post',body:{user:"Jill",password:'hill',post:"He broke his crown!"}}
const invalidRequest={method:'post',body:{user:"Jill",password:'beanstock',post:"Jack is cool..."}}
it("returns a 401 unauthorized status if the wrong credentials are sent",()=>{
const mockApiCall=mockAPI.simulateAsyncCall(invalidRequest)
return mockApiCall.then(response=>{
expect(response.status).toBe(401)
expect(mockAPI.db).toEqual(mockDatabase)
})
})
it("returns a 200 status and adds the post to the database",()=>{
const newDatabase={
users:[
{
name:"Jack",
passwordHash:"dasdKDKDJSLASDLASDJSAasdsdc123"
posts:["I just bought some magic beans!"]
},
{
name:"Jill",
passwordHash:"dasdKDKDJSLASDLASDJSAasdsdc123"
posts:["Jack fell down!","He broke his crown!"]
},
]
}
const mockApiCall=mockAPI.simulateAsyncCall(validRequest)
return mockApiCall.then(response=>{
expect(response.status).toBe(200)
expect(mockAPI.db).toEqual(newDatabase)
})
})
})
})
要開始使用 Jest,你只需要安裝它:npm install jest –save-dev
并在你的 package.json 文件中包含一個測試命令,如下所示:
"scripts":{
"test":" jest"
}
Jest 最初是 Jasmine 的一個分支,因此您可以執行我們上面描述的所有操作,甚至更多。“describe”塊的基本模式和包含一個或多個“expect”方法的“it”塊在 Jest 中的工作原理相同。
到目前為止,我們一直在測試確定性函數(對于給定的輸入,它們始終具有相同的輸出)。但如果我們的 API 依賴于我們無法控制的東西,該怎么辦?例如,如果我們的 API 使用第三方登錄進行身份驗證,該怎么辦?
Jest 允許您創建模擬函數,該函數返回可預測的結果,并包含額外的方法來跟蹤函數如何與 API 集成。使用 jest.fn 方法,我們可以做出如下斷言:
describe('AJAX functions with Jest', () => {
const mockUrl = '/api/users';
const mockUsers = [{ name: 'jack', name: 'jill' }];
const getUsers = jest.fn(url => mockUsers);
it('returns returns users from an api call', () => {
expect(getUsers(mockUrl)).toBe(mockUsers);
console.log(getUsers);
});
it('called getUser with a mockUrl', () => {
expect(getUsers).toHaveBeenCalledWith(mockUrl);
});
});
如果你運行這個測試并查看 console.log,你會注意到有很多方法與這個模擬函數相關聯。這些方法允許你具體定義函數的調用方式、函數應返回的內容等等。
您還可以使用 模擬整個模塊(用 jest mock 函數替換它們的方法) 。例如,您可以導入 HTTP 庫(例如 Axios)并像這樣jest.mock()
設置其方法的返回值:.get()
const axios = require('axios');
jest.mock('axios');
class Users {
static all() {
return axios.get('/users.json').then(resp => resp.data);
}
}
const mockUsers = [{ name: 'Jack' }];
const mockResponse = { data: mockUsers };
axios.get.mockResolvedValue(mockResponse);
return Users.all().then(data => expect(data).toEqual(users));
Jasmine 還有一個用于模擬 AJAX 調用的插件 ( jasmine-ajax ),但它不像 Jest 那樣靈活。它用自定義響應替換瀏覽器中的 XMLHttpRequest 對象。由于 XMLHttpRequest 存在于 DOM 中,因此您需要創建一個假 DOM(使用類似jsdom的東西)才能在后端運行它。
Jasmine 和 Jest 有很多相似之處。如果您的 API 主要由純函數組成,那么 Jest 和 Jasmine 都是不錯的選擇,可確保您的 API 按預期運行。
Jasmine 比 Jest 更快、更輕量,但功能較少。在控制臺中運行測試時,Jest 更具描述性,但如果您更注重簡約,您可能更喜歡 Jasmine。我們欣賞 Jest 中模擬函數的靈活性,因此對于復雜的 API,我們建議使用 Jest 而不是 Jasmine。
但是,使用 Jest 和 Jasmine 等測試框架也有幾個缺點。如果您有多個團隊負責應用程序的不同部分(例如:前端與后端,或原生與 Web),您可能需要為每個單獨的環境編寫和更新測試。此外,由于您實際上并未部署到網絡,因此 API 測試環境中可能會遺漏一些細節。
出于這些原因,如果您正在模擬仍在開發中的 API,那么在本地或云端生成模擬服務器會很有用。Stoplight 有一個開源模擬服務器,它可以根據 OpenAPI 文檔生成。立即開始并在獲得實時數據之前設置您的 API 測試,我們希望您發現這些 API 測試最佳實踐很有幫助!?
原文鏈接:How to Mock API Calls in Test Environments