我目前正在使用 MERN 堆疊開發一個全堆疊應用程式。我一直在為每個路由的請求處理程式撰寫單元測驗,并且在測驗錯誤案例時發現了一些困難,特別是在嘗試存根函式以拒絕承諾時
我有如下所示的相關代碼:
我的終點之一。請求處理委托給 userController
const express = require("express");
const { body } = require("express-validator");
const router = express.Router();
const userController = require("../../controllers/user");
router.post(
"/",
body("username")
.isLength({
min: 3,
max: 30,
})
.withMessage(
"Your username must be at least 3 characters and no more than 30!"
),
body("password")
.isLength({ min: 3, max: 50 })
.withMessage(
"Your password must be at least 3 characters and no more than 50!"
),
userController.createNewUser
);
上述端點的請求處理程式。我正在嘗試測驗 createNewUser。我想存根createNewUser以便引發錯誤,因此我可以測驗是否發送了 500 狀態代碼回應。
const bcrypt = require("bcryptjs");
const { validationResult } = require("express-validator");
const User = require("../models/User");
exports.createNewUser = async (req, res, next) => {
const { username, password } = req.body;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
errors: errors.array(),
});
}
try {
// Create a bcrypt salt
const salt = await bcrypt.genSalt(12);
// Hash the password
const hashedPassword = await bcrypt.hash(password, salt);
// Create a new user
const user = new User({
username,
password: hashedPassword,
});
const response = await user.save();
res.status(200).json(response);
} catch (err) {
res.status(500).json({ msg: err.message });
}
};
用戶端點的單元測驗。我不確定如何測驗回傳 500 狀態代碼的錯誤情況...
const request = require("supertest");
// const todosController = require("../controllers/todos");
const server = require("../server");
const User = require("../models/TodoItem");
const db = require("./db");
const agent = request.agent(server);
// Setup connection to the database
beforeAll(async () => await db.connect());
afterEach(async () => await db.clear());
afterAll(async () => await db.close());
describe("User endpoints test suite", () => {
describe("POST api/user", () => {
test("It should create a user successfully and return a 200 response code", async () => {
const response = await agent
.post("/api/user")
.set("content-type", "application/json")
.send({ username: "Bob", password: "12345" });
expect(response.body.username).toEqual("Bob");
expect(response.status).toBe(200);
});
});
});
uj5u.com熱心網友回復:
在創建單元測驗時,先創建一些小的東西,然后可以添加復雜性并進行重構。
下面是基于您的代碼的簡單單元和集成測驗示例。
您可以從用戶控制器開始。
// File: user.controller.js
const bcrypt = require('bcryptjs');
exports.createNewUser = async (req, res) => {
try {
// Create a bcrypt salt.
const salt = await bcrypt.genSalt(12);
// Just make it simple, show the salt.
res.status(200).json(salt);
} catch (err) {
// Other wise, return the error message.
res.status(500).json({ msg: err.message });
}
};
基于該嘗試和捕獲,您可以創建單元測驗。
// File: user.controller.spec.js
const bcrypt = require('bcryptjs');
const user = require('./user.controller');
describe('User Controller', () => {
describe('create New User', () => {
const fakeJson = jest.fn();
const fakeStatus = jest.fn().mockReturnThis();
const fakeRes = {
status: fakeStatus,
json: fakeJson,
};
const spy = jest.spyOn(bcrypt, 'genSalt');
afterEach(() => {
jest.clearAllMocks();
});
it('should return salt', async () => {
const testSalt = 'salt';
// Mock the bcrypt.genSalt, always resolved with value testSalt.
spy.mockResolvedValue(testSalt);
// Call the function under test.
await user.createNewUser(undefined, fakeRes);
// Set the expectations.
expect(fakeStatus).toHaveBeenCalledWith(200);
expect(fakeJson).toHaveBeenCalledWith(testSalt);
expect(spy.mock.calls[0][0]).toBe(12);
});
it('should return error message when error', async () => {
const error = new Error('XXX');
// Mock the bcrypt.genSalt, always resolved with value testSalt.
spy.mockRejectedValue(error);
// Call the function under test.
await user.createNewUser(undefined, fakeRes);
// Set the expectations.
expect(fakeStatus).toHaveBeenCalledWith(500);
expect(fakeJson).toHaveBeenCalledWith({ msg: error.message });
expect(spy.mock.calls[0][0]).toBe(12);
});
});
});
當您在終端上運行它時:
$ npx jest user.controller.spec.js
PASS ./user.controller.spec.js
User Controller
create New User
? should return salt (5 ms)
? should return error message when error (1 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
user.controller.js | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.511 s, estimated 1 s
Ran all test suites matching /user.controller.spec.js/i.
接下來,如果您確定您的控制器,您可以使用 express 創建集成測驗。
例如,您像這樣創建應用索引。
// File: index.js
const express = require('express');
const userController = require('./user.controller');
const router = express.Router();
router.post('/user', (req, res, next) => userController.createNewUser(req, res, next));
const app = express();
app.use('/api', router);
module.exports = app;
對于像這樣的正常和錯誤情況,您可以使用 jest 對其進行測驗。
// File: index.spec.js
const request = require('supertest');
const bcrypt = require('bcryptjs');
const server = require('./index');
const userController = require('./user.controller');
const agent = request.agent(server);
describe('App', () => {
describe('POST /', () => {
// Create spy on bcrypt.
const spy = jest.spyOn(bcrypt, 'genSalt');
const error = new Error('XXX');
afterEach(() => {
jest.clearAllMocks();
});
it('should create a salt successfully and return a 200 response code', async () => {
// This test is slow because directly call bcrypt.genSalt.
// To make it faster, mock bcrypt completely, or use spy.mockResolvedValue('SALT');
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(200);
expect(response.type).toBe('application/json');
expect(spy.mock.results[0].value).toBeDefined();
const spyResult = await spy.mock.results[0].value;
expect(response.body).toBe(spyResult)
});
it('should return 500 and error message when catch error', async () => {
// Makesure spy reject.
spy.mockRejectedValue(error);
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(500);
expect(response.type).toBe('application/json');
expect(response.body).toBeDefined();
expect(response.body.msg).toBeDefined();
expect(response.body.msg).toBe(error.message);
});
// Or play around with another spy to error alternatives.
it('should return 404 when pass to next', async () => {
// Makesure createNewUser error.
jest.spyOn(userController, 'createNewUser').mockImplementation((req, res, next) => {
// You can setup res here or other implementation to check.
// For example, do next.
next();
});
// Send post request.
const response = await agent.post('/api/user');
// Make sure the response.
expect(response.status).toBe(404);
// Method bcrypt.genSalt should not get called.
expect(spy).not.toHaveBeenCalled();
});
});
});
當您從終端運行它時:
$ npx jest index.spec.js
PASS ./index.spec.js
App
POST /
? should create a salt successfully and return a 200 response code (40 ms)
? should return 500 and error message when catch error (4 ms)
? should return 404 when pass to next (5 ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
user.controller.js | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 0.809 s, estimated 1 s
Ran all test suites matching /index.spec.js/i.
注意:不需要使用 sinon,jest 提供了mock 函式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/406790.html
標籤:
上一篇:在子類中呼叫Moq父方法
