Jest 로그인 TestCode에러

권태형·2023년 6월 16일
0

bnb Back-Server Project

목록 보기
18/31

보통 어디서 어떻게 실패하였는지 테스트 코드를 작성하면서 동작시켜보면 알아 볼 수 있는데. 정상적으로 작성한 것 같은데도 에러를 뿜어냈다.

 //로그인
  async validateUser(
    userInfo: LoginDto,
  ): Promise<{ accessToken; refreshToken } | undefined> {
    //해당 email과 일치하는 데이터를 조회
    const existUser: User = await this.userService.findByFields({
      where: { email: userInfo.email },
    });

    //email과 같은 데이터가 없을 시 에러
    if (!existUser) throw new NotFoundException('email을 확인 해주세요');

    //비밀번호 검증
    const validatePassword = await bcrypt.compare(
      userInfo.password,
      existUser.password,
    );

    //비밀번호 불일치 시 에러
    if (!validatePassword)
      throw new BadRequestException('password를 확인해 주세요');

    //토큰에 넣어줄 정보 선언
    const payload: Payload = { id: existUser.id, nickname: existUser.nickname };

    // accessToken 발급
    const accessToken = await this.createAccessToken(payload);
    // refreshToken 발급
    const refreshToken = await this.createRefreshToken(payload);

    return { accessToken, refreshToken };
  }

위 로그인 코드에 대한 test 케이스를 작성하기 위해 아래와 같이 테스트 코드를 작성하였다.

it('로그인 성공 케이스', async () => {
    const user = {
      id: 1,
      email: 'test@test.com',
      password: await bcrypt.hash('testpass', 10),
      nickname: 'testnick',
    };

    const loginDto: LoginDto = { email: 'test@test.com', password: 'testpass' };

    mockUserService.findByFields = jest.fn(() => user);

    const result = await authService.validateUser(loginDto);

    expect(result).toEqual({
      accessToken: 'accessToken',
      refreshToken: 'refreshToken',
    });
  });

어짜피 authService.validateUser()를 테스팅 하는 것이고, 해당 결과는 result에 담긴다. 그리고 그 result는 위의 코드로직에서 반환하는 return { accessToken, refreshToken }가 되어야한다.

하지만, 테스트를 실행해 보면 성공할 것이라 생각했던 것과 달리 실패가 뜨고 expect(result).toEqual({ accessToken: 'accessToken', refreshToken: 'refreshToken' })에서 result가 { accessToken: 'refreshToken', refreshToken: 'refreshToken' }를 반환하고 있다.

왜???

문제점은 각 토큰을 발급하는 함수가 실질적으로는 같은 jwtService.sign함수를 사용하고 들어가는 secret 과 expiresIn을 다르게 함으로써 서로의 값이 달라지는데, 테스트 케이스에서는 해당 구현이 똑바로 되지 않아서 반환값의 일치를 보장하지 못했다.

    // accessToken 발급
    const accessToken = await this.createAccessToken(payload);
    // refreshToken 발급
    const refreshToken = await this.createRefreshToken(payload);

//----------------------------------------------------------------

 //엑세스 토큰 생성
  async createAccessToken(payload: Payload): Promise<string> {
    const accessToken = await this.jwtService.sign(payload, {
      secret: process.env.ACCESS_JWT_SECRET,
      expiresIn: '5m',
    });
    return accessToken;
  }
  //리프레쉬 토큰 생성
  async createRefreshToken(payload: Payload): Promise<string> {
    const refreshToken = await this.jwtService.sign(payload, {
      secret: process.env.REFRESH_JWT_SECRET,
      expiresIn: '24h',
    });
    return refreshToken;
  }

따라서 각 함수가 어떠한 값을 도출해 내줄 것인지 정해줄 필요가 생겼다.

it('로그인 성공 케이스', async () => {
    const user = {
      id: 1,
      email: 'test@test.com',
      password: await bcrypt.hash('testpass', 10),
      nickname: 'testnick',
    };

    const loginDto: LoginDto = { email: 'test@test.com', password: 'testpass' };

    mockUserService.findByFields = jest.fn(() => user);

    jest
      .spyOn(authService, 'createAccessToken')
      .mockResolvedValue('accessToken');
    jest
      .spyOn(authService, 'createRefreshToken')
      .mockResolvedValue('refreshToken');

    const result = await authService.validateUser(loginDto);

    expect(result).toEqual({
      accessToken: 'accessToken',
      refreshToken: 'refreshToken',
    });
    expect(mockUserService.findByFields).toBeCalledTimes(1);
    expect(authService.createAccessToken).toBeCalledTimes(1);
    expect(authService.createRefreshToken).toBeCalledTimes(1);
  });

jest.spyOn()을 이용해 각 함수를 감시?하고, 그 함수들이 어떤결과를 내놓을지 jest.mockResolvedValue()을 통해 보장해 주었더니 정상적으로 동작하게 되었다.

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.

0개의 댓글