NestJS로 API 만들기

https://nomadcoders.co/nestjs-fundamentals


노마드코더 강의를 참고하고 있습니다.

 


spec.ts

Nest.js에서 spec.ts 파일은 유닛 테스트를 작성하는 데 사용하는 파일이다.

특정 모듈, 서비스, 컨트롤러 등의 단위에 대해 테스트를 정의하는 데 사용한다.

 

일반적으로 Nest.js에서 유닛 테스트를 하기 위해 Jest 프레임워크를 사용한다.

package.json 파일을 보면 이미 jest 설정이 되어있는 것을 확인할 수 있다.

 

Jest

  • describe 함수

describe 함수는 테스트 파일이나 테스트 블록을 정의할 때 사용한다.

describe('Math operations', () => {
  // 덧셈에 대한 테스트 그룹
  describe('Addition', () => {
    it('should correctly add two numbers', () => {
      const result = 1 + 2;
      expect(result).toBe(3);
    });
  });

  // 뺄셈에 대한 테스트 그룹
  describe('Subtraction', () => {
    it('should correctly subtract two numbers', () => {
      const result = 5 - 2;
      expect(result).toBe(3);
    });
  });
});

 

  • it 함수

it 함수는 테스트 케이스를 정의할 때 사용한다.

it('테스트 설명', () => {
  // 테스트 로직
});

 

  • expect 함수

expect 함수는 예상한 결과와 실제 결과를 비교하고, 테스트가 성공적으로 통과했는지 여부를 판단한다.

밑에 예시에서 result가 배열의 인스턴스인지 검사한다.

it('should return an array', () => {
  const result = someFunction();
  expect(result).toBeInstanceOf(Array);
});

 


1. service.spec.ts

getAll 메서드 테스트

  1. getAll 메서드로 가지고 온 값이 Array 인스턴스인지 확인한다.
describe('MoviesService', () => {
  describe('getAll', () => {
    it('should return an array', () => {
      const result = service.getAll();
      expect(result).toBeInstanceOf(Array);
    });
  });
});

 

getOne 메서드 테스트

  1. service.create로 영화 데이터를 만든다.
  2. getOne 메서드로 id가 1인 영화 데이터를 가지고 와 id가 1이 맞는지 비교한다.
  3. id가 1이 아니라면(getOne(999)) 404 에러를 발생시킨다.
describe('MoviesService', () => {
  describe('getOne', () => {
    it('should return a movie', () => {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const movie = service.getOne(1);
      expect(movie).toBeDefined();
      expect(movie.id).toEqual(1);
    });

    it('should throw 404 error', () => {
      try {
        service.getOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});

 

deleteOne 메서드 테스트

  1. service.create로 영화 데이터를 만든다.
  2. getAll 메서드로 영화의 길이를 변수에 저장한다.
  3. deleteOne 메서드로 id가 1인 영화를 삭제한다.
  4. 그 후 다시 getAll 메서드로 영화의 길이를 변수에 저장해 영화를 삭제하기 전과 후의 값을 비교한다.
  5. 없는 id의 영화(deleteOne(999))를 삭제하면 404 에러를 발생시킨다.
describe('MoviesService', () => {
  describe('deleteOne', () => {
    it('deletes a movie', () => {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const beforeDelete = service.getAll().length;
      service.deleteOne(1);

      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(beforeDelete);
    });

    it('should return a 404', () => {
      try {
        service.deleteOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});

 

create 메서드 테스트

  1. getAll 메서드로 영화의 길이를 변수에 저장한다.
  2. create 메서드로 새로운 영화를 생성한다.
  3. 그 후 다시 getAll 메서드로 영화의 길이를 변수에 저장해 영화를 생성하기 전과 후의 값을 비교한다.
describe('MoviesService', () => {
  describe('create', () => {
    it('should create a movie', () => {
      const beforeCreate = service.getAll().length;

      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      const afterCreate = service.getAll().length;
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    });
  });
});

 

update 메서드 테스트

  1. service.create로 영화 데이터를 만든다.
  2. update 메서드로 id가 1인 영화의 title을 수정한다.
  3. getOne 메서드로 해당 영화를 가져와 영화의 title이 'Updated Test'가 맞는지 비교한다.
  4. 없는 id의 영화(update())를 수정하면 404 에러를 발생시킨다.
describe('MoviesService', () => {
  describe('update', () => {
    it('should throw a NotFoundException', () => {
      service.create({
        title: 'Test Movie',
        year: 2024,
        genres: ['Test'],
      });

      service.update(1, { title: 'Updated Test' });

      const movie = service.getOne(1);
      expect(movie.title).toEqual('Updated Test');

      try {
        service.update(999, {});
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});

 

2. 터미널에서 확인하기

터미널에서 아래 명령어를 실행한다.

모든 spec 파일에 대해 테스트가 진행된다.

 

:watch 옵션을 사용하면 저장할 때마다 자동으로 테스트를 시작한다.

npm run test
또는
npm run test:watch

 

3. 전체 코드

  • src/movies/movies.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';
import { NotFoundException } from '@nestjs/common';

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

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

    service = module.get<MoviesService>(MoviesService);

    // 테스트에 사용될 영화 객체 생성, id는 자동으로 생성됨
    testMovie = {
      title: 'Test Movie',
      year: 2024,
      genres: ['Test'],
    };
  });

  describe('getAll', () => {
    it('should return an array', () => {
      expect(service.getAll()).toBeInstanceOf(Array);
    });
  });

  describe('getOne', () => {
    it('should return a movie', () => {
      service.create(testMovie);

      const movie = service.getOne(1);
      expect(movie).toBeDefined();
      expect(movie.id).toEqual(1);
    });

    it('should throw 404 error', () => {
      try {
        service.getOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });

  describe('deleteOne', () => {
    it('deletes a movie', () => {
      service.create(testMovie);

      const beforeDelete = service.getAll().length;
      
      service.deleteOne(1);

      const afterDelete = service.getAll().length;
      expect(beforeDelete).toBeLessThan(afterDelete);
    });

    it('should return a 404', () => {
      try {
        service.deleteOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });

  describe('create', () => {
    it('should create a movie', () => {
      const beforeCreate = service.getAll().length;

      service.create(testMovie);

      const afterCreate = service.getAll().length;
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    });
  });

  describe('update', () => {
    it('should throw a NotFoundException', () => {
      service.create(testMovie);

      service.update(1, { title: 'Updated Test' });

      const movie = service.getOne(1);
      expect(movie.title).toEqual('Updated Test');

      try {
        service.update(999, {});
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
      }
    });
  });
});

+ Recent posts