๐Ÿฅณ NEST.JS๋กœ API ๋งŒ๋“ค๊ธฐ part 2

hwakyungChoiยท2020๋…„ 12์›” 31์ผ
0
post-thumbnail

๐Ÿฆพ ๊ฐ•์˜ ํ›„๊ธฐ

  • ํŒŒํŠธ 2์—์„œ๋Š” Jest๋ฅผ ์ด์šฉํ•œ ์œ ๋‹› ํ…Œ์ŠคํŠธ์™€ e2e ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค.
  • Jest๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ๋กœ .spce.tsย ๋กœ ๋˜์–ด ์žˆ๋Š” ํŒŒ์ผ์ด ํ…Œ์ŠคํŠธ ํŒŒ์ผ์ด๋‹ค.
  • Jest๋Š” .spec.ts ํŒŒ์ผ๋“ค์„ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ๋˜์–ด ์žˆ๋‹ค.
  • ์œ ๋‹›ํ…Œ์ŠคํŠธ๋Š” function์„ ๋”ฐ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์„œ๋น„์Šค์—์„œ ๋ถ„๋ฆฌ๋œ ์œ ๋‹›์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • e2e ํ…Œ์ŠคํŠธ๋Š” ํŽ˜์ด์ง€๋กœ ๊ฐ€๋ฉด ํŠน์ • ํŽ˜์ด์ง€๊ฐ€ ๋‚˜์™€์•ผ ํ•˜๋Š” ์‚ฌ์šฉ์ž ๊ด€์ ์˜ ํ…Œ์ŠคํŠธ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ทจํ• ๋งŒํ•œ ์•ก์…˜์„ ํ™•์ธ ์ „์ฒด ์‹œ์Šคํ…œ์„ ํ…Œ์ŠคํŠธ์ด๋‹ค.
  • ์ฒ˜์Œ Jest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ๋‹› ํ…Œ์ŠคํŠธ์™€ e2eํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์•˜๋Š”๋ฐ ๊ฐœ๋ฐœ์ž๋“ค์ด ์–ด๋–ป๊ฒŒ ํšจ์œจ์ ์ด๊ณ  ์—๋Ÿฌ๊ฐ€ ์—†๋Š” ๊ฐœ๋ฐœ์„ ํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”์ง€ ์‹ค์งˆ์ ์œผ๋กœ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ฐ•์˜์˜€๋‹ค.

๐Ÿฆ„ ์ฝ”๋“œ

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

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

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

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

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

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

  describe('getOne', () => {
    it('should return a movie', () => {
      service.create({
        title: 'Test Movie',
        genres: ['test'],
        year: 2000,
      });
      const movie = service.getOne(1);
      expect(movie).toBeDefined();
    });

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

  describe('deleteOne', () => {
    it('deletes a movie', () => {
      service.create({
        title: 'Test Movie',
        genres: ['test'],
        year: 2000,
      });
      const beforeDelete = service.getAll().length;
      service.deleteOne(1);
      const afterDelete = service.getAll().length;
      expect(afterDelete).toBeLessThan(beforeDelete);
    });

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

  describe('create', () => {
    it('should create a movie', () => {
      const beforeCreate = service.getAll().length;
      service.create({
        title: 'Test Movie',
        genres: ['test'],
        year: 2000,
      });
      const afterCreate = service.getAll().length;
      expect(afterCreate).toBeGreaterThan(beforeCreate);
    });
  });

  describe('update', () => {
    it('should update a movie', () => {
      service.create({
        title: 'Test Movie',
        genres: ['test'],
        year: 2000,
      });
      service.update(1, { title: 'Updated Test' });
      const movie = service.getOne(1);
      expect(movie.title).toEqual('Updated Test');
    });

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



//app.e2e-spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('AppController (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    app.useGlobalPipes(
      new ValidationPipe({
        whitelist: true,
        forbidNonWhitelisted: true,
        transform: true,
      }),
    );
    await app.init();
  });

  it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Welcome to my Movie API');
  });

  describe('/movies', () => {
    it('GET', () => {
      return request(app.getHttpServer())
        .get('/movies')
        .expect(200)
        .expect([]);
    });
    it('POST 201', () => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test',
          year: 2000,
          genres: ['test'],
        })
        .expect(201);
    });
    it('POST 400', () => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({
          title: 'Test',
          year: 2000,
          genres: ['test'],
          other: 'thing',
        })
        .expect(400);
    });
    it('DELETE', () => {
      return request(app.getHttpServer())
        .delete('/movies')
        .expect(404);
    });
  });

  describe('/movies/:id', () => {
    it('GET 200', () => {
      return request(app.getHttpServer())
        .get('/movies/1')
        .expect(200);
    });
    it('GET 404', () => {
      return request(app.getHttpServer())
        .get('/movies/999')
        .expect(404);
    });
    it('PATCH 200', () => {
      return request(app.getHttpServer())
        .patch('/movies/1')
        .send({ title: 'Updated Test' })
        .expect(200);
    });
    it('DELETE 200', () => {
      return request(app.getHttpServer())
        .delete('/movies/1')
        .expect(200);
    });
  });
});

0๊ฐœ์˜ ๋Œ“๊ธ€