【发布时间】:2021-09-19 09:07:45
【问题描述】:
我无法让 Sinon 正确模拟 redis 以进行单元测试。测试用例通过了,但 Mocha 仍然每次都因 redis 连接错误而崩溃,我无法深入了解它。经过几天的工作并通过 Stackoverflow 梳理我仍然无法解决它,所以是时候问比我更好的头脑了。
我从一个将导出应用程序的server.ts 文件开始,因此可以在外部加载它以进行最终运行时配置或加载到测试套件中:
import express, { Application } from "express";
import bodyParser from "body-parser";
import auth from "./routes/authRoutes";
const createServer = () => {
const app: Application = express();
app.use(bodyParser.json());
app.get("/", (_req, res: Response, _next) => {
res.json({
message: "Hello World",
});
});
app.use("/auth", auth);
return app;
};
export default createServer;
authRoutes.ts 文件相当简单,为了简洁起见,我合并了验证中间件和端点逻辑:
import { Router, Request, Response, NextFunction } from "express";
import { check, validationResult } from "express-validator";
import redisCache from "../data/redis-cache";
const router = Router();
const postAuth = async (req: Request, res: Response, _next: NextFunction) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json(errors.array());
}
const sessionId = Math.random().toString();
await redisCache.setAsync(sessionId, "session1");
return res.status(200).json({ sessionId: sessionId });
};
router.post(
"/login",
[
check("body").exists().withMessage("No Post Body"),
],
postAuth
);
export default router;
我还设置了一个redis-cache.ts 文件来承诺和导出我需要的redis函数:
import redis from "redis";
import { promisify } from "util";
const client = redis.createClient({
host: process.env.REDIS_HOST || "localhost",
port: process.env.REDIS_PORT ? +process.env.REDIS_PORT : 6379,
});
const getAsync = promisify(client.get).bind(client);
const setAsync = promisify(client.set).bind(client);
export default {
getAsync,
setAsync,
};
测试套件index.spec.ts很简单,设置了3个测试:
import chai, { expect } from "chai";
import chaiHttp from "chai-http";
import * as sinon from "sinon";
import createServer from "../src/server";
import redis from "redis";
chai.use(chaiHttp);
chai.should();
describe("auth routes", function () {
const mock = sinon.createSandbox();
before(function () {
mock.stub(redis, "createClient").returns({
set: (key: string, value: string, cb: (e: Error | null) => void) => {
console.log(`mocked set, request: ${key} -> ${value}`);
return cb(null);
},
get: (key: string, cb: (e: Error | null) => void) => {
console.log(`mocked get, request: ${key} `);
return cb(null);
},
quit: (_cb: () => void) => {
console.log(`mocked quit method`);
},
} as any);
});
after(function () {
mock.restore();
});
describe("#GET/login", function () {
it("responds with 404", function (done) {
const app = createServer();
chai
.request(app)
.get("/auth/login")
.end((err: any, res: any) => {
expect(err).to.be.null;
expect(res.status).to.equal(404);
done();
});
});
});
describe("#POST/login", function () {
const app = createServer();
function requestSend() {
return chai.request(app).post("/auth/login");
}
describe("without body", function () {
it("responds with 422", function (done) {
requestSend().end(function (err: any, res: any) {
if (err) return done(err);
expect(res.status).to.equal(422);
done();
});
});
it("returns error when no post body sent", function (done) {
requestSend().end(function (err: any, res: any) {
if (err) return done(err);
expect(res.body).to.be.a("array");
const body = res.body as { msg: string }[];
const messageIndex = body.findIndex(
(el) => el.msg === "No Post Body"
);
expect(messageIndex).to.not.equal(-1);
done();
});
});
});
});
});
现在我用 Mocha 运行测试并得到以下结果:
auth routes
Uncaught error outside test suite
#GET/login
✔ responds with 404
#POST/login
without body
✔ responds with 422 (45ms)
✔ returns error when no post body sent
3 passing (217ms)
1 failing
1) auth routes
Uncaught error outside test suite:
Uncaught Redis connection to localhost:6379 failed - connect ECONNREFUSED 127.0.0.1:6379
Error: connect ECONNREFUSED 127.0.0.1:6379
如您所见,所有测试都通过了,但 redis 仍在尝试在测试套件之外进行连接,我不知道如何绕过它。如果我在我的authRoutes.ts 文件中注释掉对await redisCache.setAsync 的调用并运行测试,全部为绿色且没有错误。
我花了好几个小时在谷歌上搜索并尝试了一些没有运气的东西,我很确定我错过了一些东西,但我找不到它。任何帮助将不胜感激。
我按照this blog post 创建了一个类似的设置并且它可以工作,这让我相信这可以完成并且错误是我的一部分。
【问题讨论】:
标签: typescript express redis mocha.js sinon