TDD - Jest - Mocking

SSAD·2023년 3월 2일
0

BackEnd

목록 보기
43/44
post-custom-banner

Mocking

Mocking은 단위 테스트를 작성할 때

해당 코드가 의존하는 부분을 가짜(mock)으로 대체하는 기법

  • 테스트하려는 코드가 의존하는 부분을 직접 생성하기 부담스러운 경우 mocking 을 사용

  • Mocking은 실제 객체인 척하는 가짜 객체를 생성하는 매커니즘을 제공

  • 테스트가 실행되는 동안 Mocking 객체가 호출되거나,

    어떤 아웃풋을 반환하는지 등을 기억하기에 어떻게 사용되는지 검증이 가능

  • Mocking을 이용하면 구체적으로 구현해야 하는 실제 객체 사용보다 훨씬 빠르고,
    동일한 결과를 내는 테스트를 작성 가능

  • NestJS는 Dependency Injection을 통해 각 Module을 캡슐화하여
    서로 의존성을 최대한 배제하고 주입하여 사용하는 특징이 있음

  • NestJS의 Test환경을 조성할 경우 의존성을 주입하지 않고 의존성 자체를 Mocking해야 함

  • unit Test를 하기 위해 실제 코드가 실행되는 환경과 같은 환경을 조성


실습

  • Class 속성을 사용해서 AppService를 Mocking
import { Test, TestingModule } from '@nestjs/testing';
import { AppController } from './app.controller';
import { AppService } from './app.service';

class MockAppService {
  getHello() {
    return 'Hello World!';
  }
}

describe('AppController', () => {
  let appController: AppController;

  beforeEach(async () => {
    const app: TestingModule = await Test.createTestingModule({
      controllers: [AppController],
      providers: [
        {
          provide: AppService,
          useClass: MockAppService,
        },
      ],
    }).compile();

    appController = app.get<AppController>(AppController);
  });

  describe('getHello', () => {
    it('return Hello World!', () => {
      expect(appController.getHello()).toBe('Hello World!');
    });
  });
});

실습2

  • Repository Mocking하여 독립된 환경에서 Service를 테스트
import { ConflictException } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { UserService } from '../user.service';
import { User } from '../entities/user.entity';

class MockUserRepository {
  mydb = [{ email: 'a@a.com', password: '0000', mobileNumber: '01011111111' }];

  findOne({ email }) {
    const users = this.mydb.filter((el) => el.email === email);
    if (users.length) return users[0];
    return null;
  }

  save({ email, password, mobileNumber }) {
    this.mydb.push({ email, password, mobileNumber });
    return { email, password, mobileNumber };
  }
}

describe('UserService', () => {
  let userService: UserService;

  beforeEach(async () => {
    const userModule: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: getRepositoryToken(User),
          useClass: MockUserRepository,
        },
      ],
    }).compile();

    userService = userModule.get<UserService>(UserService);
  });

  describe('create', () => {
    it('이미 존재하는 이메일 검증하기!!', async () => {
      const myData = {
        email: 'a@a.com',
        password: '1234',
        mobileNumber: '01011111111',
      };
      try {
        await userService.create({ ...myData });
      } catch (error) {
        expect(error).toBeInstanceOf(ConflictException);
      }
    });

    it('회원 등록 검증', async () => {
      const myData = {
        email: 'bbb@bbb.com',
        password: '1234',
        mobileNumber: '01011111111',
      };

      const myResultData = {
        email: 'bbb@bbb.com',
        password: '1234',
        mobileNumber: '01011111111',
      };

      const result = await userService.create({ ...myData });
      expect(result).toStrictEqual(myResultData);
    });
  });

});
  • TestingModule을 생성할 때 UserRepository를 mocking

    • UserRepository가 사용할 findOne method와 save method를 mocking
  • it에 mock 값을 넣어서 create할 때 올바른 값을 반환하는지 확인하는 테스트 코드 작성

profile
learn !
post-custom-banner

0개의 댓글