본문 바로가기
카테고리 없음

[Nest.js][jest] controller, service 계층 단위 테스트

by 웅대 2024. 11. 10.
728x90
반응형

배경

이전 포스팅에서 Nest.js의 repository 계층 단위 테스트를 알아보았다.

https://growth-coder.tistory.com/316

 

[Nest.js][jest] Repository 계층 단위 테스트

jest이전에 jest 간단 사용법에 대해 포스팅 한 적이 있다.https://growth-coder.tistory.com/284 [Express] jest로 단위 테스트 하는 법이번 포스팅에서는 jest를 사용해서 단위 테스트를 진행해보려고 한다

growth-coder.tistory.com

 

이번 포스팅에서는 controller와 service 계층의 단위 테스트를 구현해보려고 한다.

 

User 엔티티와 레포지토리 계층은 이전 포스팅과 동일하다.

 

service 계층 단위 테스트 

서비스 계층 코드는 다음과 같다.

import { Injectable } from '@nestjs/common';
import { UserRepository } from './user.repository';
import { User } from './user.entity';

@Injectable()
export class UserService {
  constructor(private readonly userRepository: UserRepository) {}

  async createUser(
    username: string,
    password: string,
  ): Promise<User> {
    return this.userRepository.createUser(username, password);
  }

  async findByUserName(username: string): Promise<User | null> {
    return this.userRepository.findByUserName(username);
  }
}

 

현재 UserService는 UserRepository에 의존을 하고 있기 때문에 UserRepository의 메소드들을 모킹한다.

 

describe('UserService', () => {
  let userService: UserService;
  const newUser = {
    id: 1,
    username: 'test',
    password: 'test',
  };
  const user = new User();
  Object.assign(user, newUser);

  const userRepository = {
    createUser: jest.fn().mockResolvedValue(user),
    findByUserName: jest.fn((username) =>
      username === 'test' ? Promise.resolve(user) : Promise.resolve(null),
    ),
  };
};

 

createUser는 미리 만들어둔 User를 Promise로 반환하고 findByUserName은 username이 test일 때만 User를 Promise로 반환한다.

 

import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';
import { User } from './user.entity';

describe('UserService', () => {
  let userService: UserService;
  const newUser = {
    id: 1,
    username: 'test',
    password: 'test',
  };
  const user = new User();
  Object.assign(user, newUser);

  const userRepository = {
    createUser: jest.fn().mockResolvedValue(user),
    findByUserName: jest.fn((username) =>
      username === 'test' ? Promise.resolve(user) : Promise.resolve(null),
    ),
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        {
          provide: UserRepository,
          useValue: userRepository,
        },
      ],
    }).compile();

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

  it('should be defined', () => {
    expect(userService).toBeDefined();
  });

  it('createUser', async () => {
    const createdUser = await userService.createUser('test', 'test');
    expect(createdUser).toBe(user);
  });
  it('findByUserName', async () => {
    const findUser = await userService.findByUserName('test');
    expect(findUser).toBe(user);
  });
});

 

controller 계층 단위 테스트 

컨트롤러 계층 코드는 다음과 같다.

import { Controller, Post, Get, Body, Param } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post()
  async createUser(
    @Body('username') username: string,
    @Body('password') password: string,
  ): Promise<User> {
    return this.userService.createUser(username, password);
  }

  @Get(':username')
  async findByUserName(@Param('username') username: string): Promise<User | null> {
    return this.userService.findByUserName(username);
  }
}

 

역시 UserService를 모킹한다.

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

  const mockUser: User = {
    id: 1,
    username: 'test',
    password: 'test',
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [UserController],
      providers: [
        {
          provide: UserService,
          useValue: {
            createUser: jest.fn().mockResolvedValue(mockUser),
            findByUserName: jest.fn().mockResolvedValue(mockUser),
          },
        },
      ],
    }).compile();

    userController = module.get<UserController>(UserController);
    userService = module.get<UserService>(UserService);
  });
});

 

이제 테스트 코드를 작성하면 된다.

import { Test, TestingModule } from '@nestjs/testing';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { User } from './user.entity';

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

  const mockUser: User = {
    id: 1,
    username: 'test',
    password: 'test',
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      controllers: [UserController],
      providers: [
        {
          provide: UserService,
          useValue: {
            createUser: jest.fn().mockResolvedValue(mockUser),
            findByUserName: jest.fn().mockResolvedValue(mockUser),
          },
        },
      ],
    }).compile();

    userController = module.get<UserController>(UserController);
    userService = module.get<UserService>(UserService);
  });

  describe('createUser', () => {
    it('should create a new user', async () => {
      const username = 'test';
      const password = 'test';

      const result = await userController.createUser(username, password);

      expect(result).toEqual(mockUser);
      expect(userService.createUser).toHaveBeenCalledWith(username, password);
    });
  });

  describe('findByUserName', () => {
    it('should return a user by username', async () => {
      const username = 'test';

      const result = await userController.findByUserName(username);

      expect(result).toEqual(mockUser);
      expect(userService.findByUserName).toHaveBeenCalledWith(username);
    });

    it('createUser not found', async () => {
      jest.spyOn(userService, 'findByUserName').mockResolvedValueOnce(null);

      const result = await userController.findByUserName('test');

      expect(result).toBeNull();
      expect(userService.findByUserName).toHaveBeenCalledWith('test');
    });
  });
});
728x90
반응형

댓글