[Jest 삽질기] 테스트할 함수 안에 다른 함수(외부 모듈)를 사용하고 있다면?

긴가민가·2023년 2월 7일
0

Jest 삽질기

목록 보기
1/1
post-thumbnail

아래는 필자가 실제 사용하고 있는 미들웨어 로직입니다.
해당 함수를 단위 테스트하려고 합니다.

// test.middleware.ts
import CError, { ERROR_MESSAGE } from "@utils/error";
import HTTP_STATUS_CODE from "@utils/http-status-code";
import { NextFunction, Request, Response } from "express";
import { validationResult } from "express-validator";

/**
 * @description 파라미터 유효성 검사하는 미들웨어
 */
export default async (req: Request, res: Response, next: NextFunction) => {
  const errors = validationResult(req);

  if (!errors.isEmpty()) {
    const error = new CError(ERROR_MESSAGE.INVALID_VALUE, HTTP_STATUS_CODE.INVALID_VALUE);
    res.error(error);

    return;
  }

  next();
};

함수 안에 사용하고 있는 validationResult 라는 함수가 있습니다.
함수의 반환값에 따라 수행되는 작업이 달라져요..
테스트에선 validationResult 함수를 호출하지 않고 테스트를 하려고 합니다.
if 조건의 !errors.isEmpty() 값을 다르게 해야 하는데, 어떻게 해야할까요?😯

Mocking modules

jest.mock 함수는 자동으로 모듈을 mocking하도록 도와줍니다.

💡 Jest 공식 문서(mocking module)를 참고했어요 :)

문서의 axios 예시처럼, 필자도 비슷하게 만들어볼게요 ㅎㅎ

에러가 발생하네요.. 타입은 any, validatorResult 함수의 mockReturnValue 라는 속성은 없다고 합니다.
어찌된 일일까요..?

Jest.mocked()

Type checking이 제대로 되지 않아 생기는 문제였습니다.
Jest에서는 jest.mocked 함수를 제공하여, 객체에 jest의 mock function들을 래핑해 타입을 보장해줍니다.

💡 Jest 공식 문서(jest mocked source options)를 참고했어요 :)

코드를 조금 수정해보겠습니다.

import testMiddleware from "@middlewares/test.middleware";
import { Request, Response } from "express";
import { Result, ValidationError, validationResult } from "express-validator";

jest.mock("express-validator"); // 자동으로 mocking을 해주지만
const mockedValidationResult = jest.mocked(validationResult); // 해당 함수를 사용해 jest mocking function의 사용할 수 있도록 타입 래핑까지 처리해줌

describe("validator middleware test :)", () => {
  const req = {} as Request;
  const res = {
    error: jest.fn(),
  } as unknown as Response;
  const next = jest.fn();

  test("error handler", () => {
    mockedValidationResult.mockReturnValue({
      isEmpty: () => false,
    } as Result<ValidationError>); // 실제 사용된 부분
    testMiddleware(req, res, next);

    expect(res.error).toBeCalledTimes(1);
  });
});

이제 에러없이 동작합니다!😛

전체 테스트 코드

import testMiddleware from "@middlewares/test.middleware";
import { Request, Response } from "express";
import { Result, ValidationError, validationResult } from "express-validator";

jest.mock("express-validator");
const mockedValidationResult = jest.mocked(validationResult); // jest 함수

describe("validator middleware test :)", () => {
  const req = {} as Request;
  const res = {
    error: jest.fn(),
  } as unknown as Response;
  const next = jest.fn();

  test("error handler", () => {
    mockedValidationResult.mockReturnValue({
      isEmpty: () => false,
    } as Result<ValidationError>);
    testMiddleware(req, res, next);

    expect(res.error).toBeCalledTimes(1);
  });

  test("next", () => {
    mockedValidationResult.mockReturnValue({
      isEmpty: () => true,
    } as Result<ValidationError>);
    testMiddleware(req, res, next);

    expect(next).toBeCalledTimes(1);
  });
});


의견은 언제든 댓글로 남겨주세요. 🙂

profile
미래의 내가 참고하려고 모아가는 중 :)

0개의 댓글