wam
w__am 개발노트
wam
  • 분류 전체보기 (165)
    • CS 지식 (10)
      • 자료구조 (0)
      • 알고리즘 (0)
      • 컴퓨터 구조 (0)
      • 운영체제 (0)
      • 네트워크 (7)
      • 데이터베이스 (0)
      • 디자인 패턴 (3)
    • Frontend (131)
      • Three.js (64)
      • NPM (1)
      • Nest.js (19)
      • React (10)
      • Apollo (7)
      • TypeScript (2)
      • JavaScript (12)
      • HTML, CSS (1)
      • Jest (3)
      • E2E (5)
      • Cypress (7)
    • Database (12)
      • TypeORM (12)
    • IT 지식 (8)
      • 클라우드 서비스 (3)
      • 네트워크 (1)
      • 데이터 포맷 (2)
      • 기타 (2)
    • IT Book (2)
    • 유용한 사이트 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 🐱 Github

인기 글

태그

  • 렌더링 성능 최적화
  • type-graphql
  • axeshelper
  • three.js 구성 요소
  • threejs 개발 할 때 도움을 줄 수 있는 유틸리티
  • e.preventdefault()
  • isabstract
  • react 성능 최적화
  • 스코프
  • 삼각함수
  • Interface
  • 초기 환경설정
  • getelapsedtime()
  • gridhelper
  • 디자인 패턴
  • math.cos()
  • reactive variables
  • getdelta()
  • 오프-프레미스(off-premise) 방식
  • 함수 표현식
  • 함수 선언문
  • Decorators
  • 함수 리터럴
  • API
  • 함수의 범위
  • mapped types
  • joi 에러
  • math.sin()
  • 데이터 포맷
  • 원형적인 움직임

최근 글

관리자

글쓰기 / 스킨편집 / 관리자페이지
hELLO · Designed By 정상우.
wam

w__am 개발노트

Mocking, 가짜 레파지토리, 함수 만들기
Frontend/Jest

Mocking, 가짜 레파지토리, 함수 만들기

2024. 8. 1. 22:29

 

Mocking이란

 

테스트에서 실제 객체나 함수 대신에 가짜 객체나 함수를 사용하는 기법을 말한다. 주로 테스트 환경을 제어하고, 특정 상황을 시뮬레이션하며, 테스트의 정확성을 보장하기 위해 사용된다.

 

Mock 란 가짜 함수의 실행, 가짜 클래스의 실행이다.

 

 

Mocking의 주요 목적

 

TypeORM에서 진짜 유저 Repository를 불러오지 않고 유저 서비스를 단독으로 테스트하기 위해서이다.

 

  • 의존성 제거: 테스트할 코드가 외부 시스템(예: 데이터베이스, API)과 상호작용할 때, 실제 시스템에 의존하지 않고 가짜 객체를 사용하여 독립적으로 테스트할 수 있다.


  • 예측 가능한 결과: 가짜 객체나 함수의 동작을 명확하게 정의함으로써, 테스트 결과를 예측하고 일관되게 유지할 수 있다.


  • 테스트의 안정성 향상: 외부 시스템이 불안정하거나 데이터가 변동될 경우에도 테스트가 영향을 받지 않도록 할 수 있다.


  • 테스트 속도 향상: 실제 외부 시스템과의 상호작용이 없으므로 테스트 속도가 빨라질 수 있다.

 

 

코드 설명

import { Test } from "@nestjs/testing";
import { UserService } from "./user.service";
import { getRepositoryToken } from "@nestjs/typeorm";
import { User } from "./entities/user.entity";
import { Verification } from "./entities/verification.entity";
import { JwtService } from "src/jwt/jwt.service";
import { MailService } from "src/mail/mail.service";
import { Repository } from "typeorm";

const mockRepository = {
  create: jest.fn(),
  save: jest.fn(),
  findOne: jest.fn(),
};

const mockJwtService = {
  sign: jest.fn(),
  verify: jest.fn(),
};

const mockMailService = {
  sendVerificationEmail: jest.fn(),
};

type MockRepository<T = any> = Partial<
  Record<keyof Repository<User>, jest.Mock>
>;

describe("UserService", () => {
  let service: UserService;
  let userRepository: MockRepository<User>;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      providers: [
        UserService,
        {
          // USerRepository
          provide: getRepositoryToken(User),
          useValue: mockRepository,
        },
        {
          // VerificationRepository
          provide: getRepositoryToken(Verification),
          useValue: mockRepository,
        },
        {
          // JwtService
          provide: JwtService,
          useValue: mockJwtService,
        },
        {
          // mailService
          provide: MailService,
          useValue: mockMailService,
        },
      ],
    }).compile();
    service = module.get<UserService>(UserService);
    userRepository = module.get(getRepositoryToken(User));
  });

  it("should be defined", () => {
    expect(service).toBeDefined();
  });

  describe("createAccount", () => {
    const createAccountArgs = {
      email: "test@mail.com",
      password: "123",
      role: UserRole.Client,
    };

    it("should fail if user exists", async () => {
      userRepository.findOne.mockResolvedValue({
        id: 1,
        email: "test@mail.com",
      });
      const result = await service.createAccount(createAccountArgs);
      expect(result).toMatchObject({
        ok: false,
        error: "There is a user with that email already",
      });
    });
  });

  it.todo("login");
  it.todo("findById");
  it.todo("verifyEmail");
});

위 코드는 전체 코드이다.

 

 

Test.createTestingModule() -  테스트 모듈을 설정

import { Test } from "@nestjs/testing";

const module = await Test.createTestingModule({({ ... }).compile();:
  • Test.createTestingModule을 사용하여 테스트 모듈을 설정한다.
  • 모듈에는 UserService와 UserRepository를 제공하는 설정이 포함된다.
  • compile() 메서드는 모듈을 컴파일하여 테스트에 사용할 수 있도록 한다.

 

 

import { UserService } from "./user.service";

const mockRepository = () => ({
  create: jest.fn(),
  save: jest.fn(),
  delete: jest.fn(),
  findOne: jest.fn(),
  findOneOrFail: jest.fn(),
});

type MockRepository<T = any> = Partial<
  Record<keyof Repository<User>, jest.Mock>
>;

describe("UserService", () => {
  let service: UserService;
  let userRepository: MockRepository<User>;
  
     beforeEach(async () => {
        const module = await Test.createTestingModule({
          providers: [
            UserService,
            {
              // USerRepository
              provide: getRepositoryToken(User),
              useValue: mockRepository(),
            },
            ...
          ],
        }).compile();
        service = module.get<UserService>(UserService);
        userRepository = module.get(getRepositoryToken(User));
    })
})

 

providers: [ ... ]:

  • providers 배열은 테스트 모듈에서 사용될 서비스와 그들의 의존성을 설정한다.
  • UserService는 실제 서비스이다.
  • UserRepository는 테스트용으로 모킹 된 객체로 제공된다.

 

 

useValue: { ... }:

  • useValue는 UserRepository를 모킹 할 때 사용하는 방법이다.
  • 실제 데이터베이스와 상호작용하지 않고, 테스트를 위해 가짜 기능을 제공한다.
  • find 메서드는 항상 [{ id: 1, name: 'John' }]이라는 값을 반환
  • save 메서드는 항상 { id: 1, name: 'John' }이라는 값을 반환

 

 

userService = module.get<UserService>(UserService);

  • UserService 인스턴스를 테스트 모듈에서 가져와 userService 변수에 할당한다.

 

 

userRepository = module.get<UserRepository>(UserRepository);

  • UserRepository 인스턴스를 테스트 모듈에서 가져와 userRepository 변수에 할당한다.

 

 

type MockRepository<T = any> = Partial< Record<keyof Repository<User>, jest.Mock> >;

  • 레코드는 타입 T의 요소 K의 집합으로 타입을 만들어주는 TypeScript 다.
    • let userRepository: Partial <Record<"hello", number>>;
    • 예를 들어, 요소 K는 넘버 타입의 hello 같은 것이다
    • let userRepository: Partial<Record <keyof Repository<User>, jest.Mock>>;
    • Partial이 모든 요소를 optional로 만들어 준다.
    • 레파지토리의 key를 가져오고 싶은 것이니깐 key of 붙여주기
    • 타입이 jest.mock이다.
    • 요소의 집합이란 건 User Repository의 모든 요소들을 말한다.
      • 요소란 findOne, save, create, update 같은 모든 걸 말한다.

 

 

 

저작자표시 변경금지 (새창열림)

'Frontend > Jest' 카테고리의 다른 글

Jest로 단위 테스트 코드를 구현할 때 자주 사용되는 API  (0) 2024.08.01
Jest 란  (0) 2024.08.01
    'Frontend/Jest' 카테고리의 다른 글
    • Jest로 단위 테스트 코드를 구현할 때 자주 사용되는 API
    • Jest 란
    wam
    wam

    티스토리툴바