본문 바로가기
내일배움캠프/축구팀 관리 프로젝트

축구팀 관리 프로젝트 36일차 - jwt 모의함수 구현 오류

by 코드스니펫 2024. 2. 16.
반응형

축구팀 관리 프로젝트 36일차 - jwt 모의함수 구현 오류

 

모의 함수 구현 화면

 

테스트 코드 작성 중 발견한 jwt 모의함수 구현 오류를 어떻게 해결했는지 소개하겠습니다.

 

 

jwt 모의함수 구현 오류

 

문제발견

문제는 아래 코드에서 시작됐습니다.

 

모의함수 구현 오류 발생

 

jest.spyOn(jwtService, 'verify').mockResolvedValue({ id: 1 });을 사용하여 Jest에서 jwtService.verify를 모의하려고 할 때, TypeScript에서 '{ id: number; }' 형식의 인수는 'never' 형식의 매개 변수에 할당될 수 없다는 오류가 발생했습니다.

 

typescript 오류

 

 

오류 원인 분석

이 오류는 TypeScript가 모의 함수에서 정확한 타입을 추론할 수 없어서 발생했습니다. mockResolvedValue는 인수로 전달된 값의 타입을 추론하기 때문에, { id: 1 }이라는 객체의 타입을 정확히 알 수 없어서 오류가 발생했습니다.

 

시도한 방법들

NestJS의 JwtService에서 verify 메서드의 반환값 타입을 찾으려면, 먼저 @nestjs/jwt 패키지의 공식 문서나 소스 코드를 확인해야 한다고 하는 글을 보고 바로 찾아봤습니다.

 

jwt.service.d.ts
node_modules 안에 있는 jwt.service.d.ts 파일 확인

 

확인해보니 verify는 아래처럼 되어 있었습니다.

 

verify<T extends object = any>(token: string, options?: JwtVerifyOptions): T;

 

 

제네릭 타입 T extends object = any를 사용중 이었습니다.

이는 verify 메서드가 어떤 객체 타입을 반환할지를 호출 시점에서 결정할 수 있음을 의미했습니다. 따라서, verify 메서드의 반환값 타입은 호출하는 측에서 지정한 제네릭 타입에 의해 결정된다는 사실을 알게 되었습니다. 

 

그래서 타입을 지정하면 되는건가 싶어 아래처럼 시도해보았습니다.

 

jest.spyOn(jwtService, 'verify').mockResolvedValue<{ id: number }>({ id: 1 });

 

jest.spyOn(jwtService, 'verify').mockResolvedValue<{ id: number }>({ id: 1 } as { id: number });

 

const mockPayload: { id: number } = { id: 1 };
jest.spyOn(jwtService, 'verify').mockResolvedValue(mockPayload);

 

그래도 오류는 동일하게 나타났습니다.

 

다시 여러 자료를 찾아보다가 이 블로그를 보게 되었습니다.

 

 

Carryduo | Jest를 이용한 Unit/E2E 테스트 (NestJS)

1. 개요 | 테스트 코드의 개념 - 테스트코드란 어플리케이션이 의도한대로 동작하는지 시험하기 위한 코드라고 생각한다. - 어플리케이션은 일반적으로 여러 모듈, 그리고 모듈을 구성하는 여러

coldpresso.tistory.com

 

여기서 JwtService를 모킹할 때 보지 못했던 방식을 발견할 수 있었습니다.

 

        - (3) 프로젝트에서 사용하는 외부 패키지인 JwtService 모킹(2): useValue 활용하여
      JwtService의 하위 메소드인 signAsync의 return 값을 테스트 환경에 맞춰서 모킹
        {
          provide: JwtService,
          useValue: {
            signAsync: (payload, option) => {
              return 'sample token';
            },
          },
        },

 

JwtService의 하위 메소드 중에 signAsync를 활용하는 코드였습니다. 이 방식에 대해 더 찾아보니 아래와 같은 기능을 하고 있었습니다.

 

signAsync는 일반적으로 JWT(JSON Web Token)를 생성하기 위해 사용되는 메서드입니다.
JWT는 인증 및 정보 교환을 위해 사용되는 토큰 기반의 인증 방식 중 하나입니다. signAsync 메서드는 주로 사용자 인증 후 토큰을 생성하고 반환하는 데에 사용됩니다.

보통 signAsync 메서드는 비동기적으로 작동하여 비밀 키를 사용하여 페이로드를 서명하고 토큰을 생성합니다. 생성된 토큰은 사용자의 인증 정보를 포함하며, 클라이언트와 서버 간의 통신에 사용될 수 있습니다.

모의(mock) 환경에서 signAsync 메서드를 모의하려면, 예를 들어, 테스트에서 실제로 토큰을 생성하지 않고도 모의된 토큰을 반환할 수 있습니다.

이렇게 함으로써 실제 토큰 생성 로직에 의존하지 않고도 테스트를 수행할 수 있습니다. 따라서 signAsync 메서드를 모의(mock)하기 위해 모의(mock) 함수를 사용하여 원하는 토큰을 반환하도록 설정할 수 있습니다. 이렇게 하면 테스트를 보다 간편하게 수행할 수 있습니다.

 

모의 환경에서 signAsync 메서드 모의시 장점은 실제 토큰 생성하지 않아도 모의 토큰을 반환할 수 있다는 점이 있었습니다. 원래 구현하려던 jest.spyOn(jwtService, 'verify').mockResolvedValue({ id: 1 }); 코드도 결국 토큰 발급이 정상적으로 되는지 확인하기 위함이니까 이 방식을 사용해도 되겠다고 판단했습니다.

 

 

문제 해결 방법

위 자료를 참고하여 아래와 같은 코드로 수정할 수 있었습니다.

 

jest.spyOn(jwtService, 'verify').mockImplementation(async (token: string) => {
    const payload = await jwtService.signAsync({ id: 1 });
    return payload;
});

 

여기서 mockImplementation을 사용하였는데 이 메서드는  Jest에서 모의(mock) 함수의 동작을 직접 구현할 때 사용합니다.이 메서드를 사용하면 실제 함수를 모의하여 원하는 동작을 시뮬레이션 가능한 특징이 있습니다. 이를 활용하여 토큰 생성하는 코드를 작성하였습니다.

 

mockImplementation 실행 예제
mockImplementation 동작 예제

 

▼ 이전 진행한 프로젝트들 ▼

 

 

축구팀 관리 프로젝트 34일차 - 유저테스트 시작, 취업 준비

축구팀 관리 프로젝트 34일차 - 유저테스트 시작, 취업 준비 전날 준비하던 유저테스트를 드디어 시작했습니다. 배포 전까지 나오던 오류를 하나 둘 잡고 실제로 테스트를 받기 시작하니 기분이

lemonlog.tistory.com

 

 

축구팀 관리 프로젝트 33일차 - 프로젝트 유저 테스트 준비

축구팀 관리 프로젝트 33일차 - 프로젝트 유저 테스트 준비 길고 긴 설 명절을 지나 다시 팀원들과 모여 프로젝트를 수정하는 오늘이었습니다. 곧 배포할 프로젝트를 위해 유저테스트용 자료 만

lemonlog.tistory.com