[Node.js교과서] 통합 &부하 테스트

Donghun Seol·2023년 4월 5일
0

통합테스트

npm i -D supertest

슈퍼테스트는 통합 테스트용 라이브러리로 내부적으로 익스프레스 서버를 구동시켜 가상의 요청을 보낸 뒤 결과를 검증한다. 때문에 API 단위로 테스팅할 수 있다.

먼저 app객체를 테스트에서 사용할 수 있도롤 모듈화해주고, server.js를 엔트리 포인트로 재지정해준다.

무릎을 탁...

CDS 개발하면서 이걸 사용했었더라면 서버띄운 다음에 PostMan 붙들고 일일이 파라미터 지정해서 요청날리고결괏값 확인하는 삽질이 현저하게 줄어 들었을텐데... 분명 배웠는데 활용하지 못한점이 너무 아쉽다..
(사실 제대로 공부 안했다는 증거...)

DB 설정

유닛 테스트에서는 DB연결 부분을 모킹해서 사용했지만 통합테스트는 실제 DB와 연동되어 진행된다.
따라서 테스트용 DB를 따로 설정하고 사용해야 한다. 통합테스트 전/후 DB 상태의 일관성이 유지되도록 셋업해야 함을 주의하자.

mysql을 간편하게 설정하기 위해서 docker image를 활용했다.
공홈에 문서화가 잘 되어있다.

docker pull arm64v8/mysql

docker run --name some-mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw \
-d arm64v8/mysql:tag

테스트 작성

  1. supertest의 request객체를 가져온다.
  2. 테스트 시작전 db를 초기화한다.
  3. 테스트하고자 하는 라우터에 대해서 각각의 유즈케이스를 정의한다.
  4. 관련 선결조건을 셋업하고 테스팅한다.
    쿠키나 세션과 같이 로그인 상황을 셋업하는 경우 요청을 stateful 하게 유지할 필요가 있다.
    supertest의 request.agent()를 활용하면 stateful한 요청을 테스트 할 수 있다.
const request = require('supertest');
const { sequelize } = require('../models');
const app = require('../app');

beforeAll(async () => {
  await sequelize.sync();
});

describe('POST /join', () => {
  test('로그인 안 했으면 가입', (done) => {
    request(app)
      .post('/auth/join')
      .send({
        email: 'myemail@gmail.com',
        nick: 'mynickname',
        password: 'mypassword',
      })
      .expect('Location', '/')
      .expect(302, done);
  });
});

describe('POST /join', () => {
  // 이미 로그인한 경우를 셋업하기 위해 agent객체에다 login을 미리 수행해 놓는다.
  const agent = request.agent(app);
  beforeEach((done) => {
    agent
      .post('/auth/login')
      .send({
        email: 'myemail@gmail.com',
        password: 'mypassword',
      })
      .end(done);
  });

  test('이미 로그인 했으면 redirect', (done) => {
    request(app)
      .post('/auth/login')
      .send({
        email: 'myemail@gmail.com',
        password: 'mypassword',
      })
      .expect('Location', '/')
      .expect(302, done);
  });
});

describe('POST /login', () => {
  test('가입되지 않은 회원', (done) => {
    const message = encodeURIComponent('가입되지 않은 회원입니다.');
    request(app)
      .post('/auth/login')
      .send({
        email: 'wrongemail@gmail.com',
        password: 'mypassword',
      })
      .expect('Location', `/?loginError=${message}`)
      .expect(302, done);
  });

  test('로그인 수행', (done) => {
    request(app)
      .post('/auth/login')
      .send({
        email: 'myemail@gmail.com',
        password: 'mypassword',
      })
      .expect('Location', '/')
      .expect(302, done);
  });

  test('비밀번호 틀림', (done) => {
    const message = encodeURIComponent('비밀번호가 일치하지 않습니다.');
    request(app)
      .post('/auth/login')
      .send({
        email: 'myemail@gmail.com',
        password: 'wrongpassword',
      })
      .expect('Location', `/?loginError=${message}`)
      .expect(302, done);
  });
});

describe('GET /logout', () => {
  
  test('로그인되어 있지 않으면 403', (done) => {
    request(app).get('/auth/logout').expect(403, done);
  });

  // agent객체를 셋업해서 로그인 상태로 만들어 놓는다.
  const agent = request.agent(app);
  beforeEach((done) => {
    agent
      .post('/auth/login')
      .send({
        email: 'myemail@gmail.com',
        password: 'mypassword',
      })
      .end(done);
  });

  test('로그아웃 수행', (done) => {
    agent.get('/auth/logout').expect('Location', `/`).expect(302, done);
  });
});
afterAll(async () => {
  await sequelize.sync({ force: true });
});

부하 테스트

Installing dependancies

npm i -D artillery && npm start

test

npx artillery quick --count 100 -n 50 http://localhost:8001

custom testing configuration

/*custom artillery config in json or yaml*/

npx artillery run loadtest.json

profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글