首页 > 解决方案 > 如何使用 jest 在 nodejs 中模拟 redis 客户端

问题描述

我尝试使用redis-mockusing来模拟 redisClient.js jest。但我找不到解决方案。请给我一个代码示例。我需要在controller.

redisClient.js

const redis = require('redis');
const asyncRedis = require("async-redis");

//Redis
const connection = redis.createClient(process.env.REDIS_PORT,
    {
        retry_strategy: function(options) {
          if (options.error && options.error.code === "ECONNREFUSED") {
            // End reconnecting on a specific error and flush all commands with
            // a individual error
            return new Error("The server refused the connection");
          }
          if (options.total_retry_time > 1000 * 60 * 60) {
            // End reconnecting after a specific timeout and flush all commands
            // with a individual error
            return new Error("Retry time exhausted");
          }
          if (options.attempt > 10) {
            // End reconnecting with built in error
            return undefined;
          }
          // reconnect after
          return Math.min(options.attempt * 100, 3000);
        },
    }
);

module.exports = asyncRedis.decorate(connection);

控制器

const logger = require('../../helper/logger');
const response = require("../../config/response");
const constant = require('../../config/constant');
const QuizService = require('../../services/quiz/quizService');

class QuizController {

    constructor() {
        this.quizService = new QuizService();
    }

    async getQuiz(req, res) {
        const { userId, query: { campaignId } } = req;
        try {
            const question = await this.quizService.getQuestion(userId, campaignId);

            res.send(response.res(true, constant.MSG.Quiz_FETCHED, question));

        } catch (error) {

            res.status(constant.RESPONSE.INTERNAL_ERROR.CODE)
                .send(response.res(false, error.message, null, error.code))
        }
    }
}

服务

const _ = require('lodash');
const moment = require('moment');
const { Op } = require('sequelize');
const { v4: uuidv4 } = require("uuid");
const shuffle = require('shuffle-array');
const serialize = require("serialize-javascript");
const utill = require("../../helper/util");
const redis = require("../../cache/redisClient");
const constant = require('../../config/constant');
const scoreHelper = require('./../../helper/scoreHelper');
const db = require("../../models");
const Quiz = db.quiz;
const Campaign = db.campaign;
const campaign = require('../campaign/campaignService')
const SubscriberAnswer = require('../subscriberAnswer/subscriberAnswerService')
const SubscriberProgram = require('../subscriberProgram/SubsciberProgramService')

class quizService {

    constructor() {
        this.subscriberAnswer = new SubscriberAnswer()
        this.subscriberProgram = new SubscriberProgram()
        this.campaign = new campaign()
    }

    async getQuestion(userId, campaignId) {
        const subscribedProgramData = await this._checkAvailableQuestionLimit(userId, campaignId)
        if(!subscribedProgramData){
            throw { message: constant.MSG.TRY_AGAIN }
        }
        if (subscribedProgramData.no_of_questions > 0) {
            const question = await Quiz.findQuestion(userId, campaignId);
            if (question.length) {
                const data = {
                    subscriber_id: userId,
                    campaign_id: campaignId,
                    questions_id: question[0].id
                }
                const updateData = {
                    id: subscribedProgramData.id,
                    no_of_questions: (subscribedProgramData.no_of_questions - 1)
                }
                await this.subscriberAnswer.create(data);
                await this.subscriberProgram.updateQuota(updateData);
                const id = uuidv4();
                const {answer, ...questionData } = question[0];
                const responseData = await this.handleQuestionData(id, userId, campaignId, questionData, answer);
                return responseData;
            } else {
                throw { code:constant.RESPONSE_COEDES.ALL_ANSWERED, message: constant.MSG.ANSWER_ALL }
            }
        } else {
            throw { message: constant.MSG.QUOTA_OVER }
        }
    }
}

我的单元测试代码

const QuizService = require("../../src/services/quiz/quizService");
const QuizController = require("../../src/controllers/quiz/quizController");
const quizService = new QuizService();
const quizController = new QuizController();
const httpMocks = require("node-mocks-http");

jest.mock("../../src/helper/logger");
jest.mock("../../src/cache/redisClient.js");

beforeEach(() => {
    req = httpMocks.createRequest();
    res = httpMocks.createResponse();
    next = jest.fn();
    jest.resetAllMocks();
    quizService.getQuestion = jest.fn();
});
quizService.getQuestion = jest.fn();
const response = {
    id: 1,
    name: 'Sandun',
    msisdn: '94704377575',
    otp: '1234',
    deleted: 0,
    attempts: 0,
    img_url: 'https://'
}

// This test shows how the constructor can be mocked, and how to spy on passed parameters.
describe("Test QuizController", () => {
    afterEach(() => {
      jest.resetAllMocks();
    });

    //Because getQuestion is prototype method
    it("Test - GetQuiz - Success", async () => {
        req.query.programId = 1;
        req.userId = 1;
        jest.spyOn(QuizService.prototype, "getQuestion").mockReturnValue(response);
        await quizController.getQuiz(req, res);
        expect(res.statusCode).toBe(200);
    });

});

错误

 FAIL  test/controllers/quiz.controller.test.js
  ● Test suite failed to run

    TypeError: Cannot read property 'startsWith' of undefined

       
       //Redis
     const connection = redis.createClient(process.env.REDIS_PORT,
                                  ^
           {
               retry_strategy: function(options) {
                if (options.error && options.error.code === "ECONNREFUSED") {

      at normalizeUrl (node_modules/redis-mock/lib/utils/parseRedisUrl.js:4:11)
      at Object.<anonymous>.module.exports (node_modules/redis-mock/lib/utils/parseRedisUrl.js:61:34)
      at generateUrlOptions (node_modules/redis-mock/lib/client/createClient.js:25:30)
      at unifyOptions (node_modules/redis-mock/lib/client/createClient.js:61:10)
      at Object.createClient (node_modules/redis-mock/lib/client/createClient.js:64:47)
      at Object.<anonymous> (src/cache/redisClient.js:5:26)
      at Object.<anonymous> (src/services/quiz/quizService.js:8:15)
      at Object.<anonymous> (test/controllers/quiz.controller.test.js:1:21)

标签: node.jsunit-testingredismocking

解决方案


推荐阅读