테스트를 작성하는 방식은 @nestjs/testing 패키지를 사용하여
모듈, 서비스, 컨트롤러를 테스트하는 구조로 진행됩니다.

Spring의 TDD에서 사용하는 @DisplayName, give, when, then 패턴과 유사하게 describe, beforeEach, it과 같은 Jest 구조를 통해 테스트를 작성할 수 있습니다.

여기서는 회원가입 CRUD 기능에 대한 예시를 보여드리겠습니다.

Nest.js는 기본적으로 Jest를 사용하여 테스트를 작성하며,
테스트는 컨트롤러와 서비스 레이어로 나누어 진행할 수 있습니다.

1. 회원가입 기능을 위한 기본 코드 (CRUD 예시)

먼저, 사용자 관리 기능을 제공하는 기본적인 서비스와 컨트롤러가 필요합니다.

Users Service (users.service.ts)

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Injectable()
export class UsersService {
  private users = [];

  create(createUserDto: CreateUserDto) {
    const newUser = { id: Date.now(), ...createUserDto };
    this.users.push(newUser);
    return newUser;
  }

  findAll() {
    return this.users;
  }

  findOne(id: number) {
    return this.users.find(user => user.id === id);
  }

  update(id: number, updateUserDto: UpdateUserDto) {
    const userIndex = this.users.findIndex(user => user.id === id);
    if (userIndex > -1) {
      this.users[userIndex] = { ...this.users[userIndex], ...updateUserDto };
      return this.users[userIndex];
    }
    return null;
  }

  remove(id: number) {
    const userIndex = this.users.findIndex(user => user.id === id);
    if (userIndex > -1) {
      const deletedUser = this.users.splice(userIndex, 1);
      return deletedUser;
    }
    return null;
  }
}

Users Controller (users.controller.ts)

import { Controller, Get, Post, Body, Param, Delete, Patch } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }

  @Get()
  findAll() {
    return this.usersService.findAll();
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(+id);
  }

  @Patch(':id')
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
    return this.usersService.update(+id, updateUserDto);
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return this.usersService.remove(+id);
  }
}

2. 테스트 코드 작성 (users.service.spec.ts)

회원가입과 관련된 CRUD 기능에 대한 테스트 코드를 작성합니다.

jest에서는 describe, beforeEach, it과 같은 구조를 사용하여 테스트 케이스를 그룹화하고 실행합니다.

Users Service Test (users.service.spec.ts)

import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

describe('UsersService', () => {
  let service: UsersService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UsersService],
    }).compile();

    service = module.get<UsersService>(UsersService);
  });

  describe('create', () => {
    it('should create a new user', () => {
      // given
      const createUserDto: CreateUserDto = { name: 'John', age: 25 };
      
      // when
      const result = service.create(createUserDto);

      // then
      expect(result).toEqual(expect.objectContaining({
        id: expect.any(Number),
        name: 'John',
        age: 25
      }));
    });
  });

  describe('findAll', () => {
    it('should return all users', () => {
      // given
      const user1 = service.create({ name: 'John', age: 25 });
      const user2 = service.create({ name: 'Doe', age: 30 });

      // when
      const result = service.findAll();

      // then
      expect(result).toEqual([user1, user2]);
    });
  });

  describe('findOne', () => {
    it('should return a user by id', () => {
      // given
      const user = service.create({ name: 'John', age: 25 });

      // when
      const result = service.findOne(user.id);

      // then
      expect(result).toEqual(user);
    });

    it('should return undefined if user does not exist', () => {
      // when
      const result = service.findOne(999);

      // then
      expect(result).toBeUndefined();
    });
  });

  describe('update', () => {
    it('should update a user by id', () => {
      // given
      const user = service.create({ name: 'John', age: 25 });
      const updateUserDto: UpdateUserDto = { age: 26 };

      // when
      const result = service.update(user.id, updateUserDto);

      // then
      expect(result.age).toBe(26);
    });

    it('should return null if user does not exist', () => {
      // when
      const result = service.update(999, { age: 26 });

      // then
      expect(result).toBeNull();
    });
  });

  describe('remove', () => {
    it('should delete a user by id', () => {
      // given
      const user = service.create({ name: 'John', age: 25 });

      // when
      const result = service.remove(user.id);

      // then
      expect(result).toEqual([user]);
      expect(service.findAll()).toHaveLength(0);
    });

    it('should return null if user does not exist', () => {
      // when
      const result = service.remove(999);

      // then
      expect(result).toBeNull();
    });
  });
});

테스트 코드 설명

1. beforeEach: 각 테스트 케이스 실행 전에 Nest.js의 TestingModule을 통해 UsersService 인스턴스를 생성합니다.

2. describe: 테스트 케이스들을 그룹화합니다.
예를 들어, create, findAll, findOne 등으로 나누어 테스트 그룹을 만듭니다.

3. it: 개별 테스트 케이스를 정의합니다.
각 테스트 케이스는 주어진 상황에서 기대하는 결과를 검증합니다.

4. expect: 테스트의 결과를 검증하는 데 사용합니다.
예를 들어, 새로운 사용자가 생성되었는지, 데이터가 잘 반환되는지 확인합니다.

3. 테스트 실행

테스트는 다음 명령어로 실행할 수 있습니다.

npm run test

Nest.js는 Jest를 기본으로 제공하므로, 이 명령어로 모든 테스트가 실행됩니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글