DS-Corner-Study / YUZ

0 stars 1 forks source link

11장 노드 서비스 테스트하기 #26

Open yellow-jam opened 8 months ago

yellow-jam commented 8 months ago
  1. 테스트 준비하기
  2. 유닛 테스트
  3. 테스트 커버리지
  4. 통합 테스트
  5. 부하 테스트
  6. 프로젝트 마무리
yellow-jam commented 8 months ago

1. 테스트 준비

9장의 NodeBird 서비스를 그대로 사용 npm i -D jest

package.json

"scripts": {
    "start": "nodemon app",
    "test": "jest"
  },

middlewares/index.test.js 에 테스트 코드 작성 후 npm test로 테스트 실행

image

image

yellow-jam commented 8 months ago

2. 유닛 테스트

실제 NodeBird의 코드를 테스트해보기 middlewares/index.js에 있는 isLoggedIn, isNotLoggedIn 함수를 테스트

https://inpa.tistory.com/entry/JEST-%F0%9F%93%9A-%EB%AA%A8%ED%82%B9-mocking-jestfn-jestspyOn

모킹

controllers/user.test.js 파일

jest.mock('../models/user');
const User = require('../models/user');
const { follow } = require('./user');

describe('follow', () => {
  const req = {
    user: { id: 1 },
    params: { id: 2 },
  };
  const res = {
    status: jest.fn(() => res),
    send: jest.fn(),
  };
  const next = jest.fn();

  test('사용자를 찾아 팔로잉을 추가하고 success를 응답해야 함', async () => {
    User.findOne.mockReturnValue({
      addFollowing(id) {
        return Promise.resolve(true);
      }
    });
    await follow(req, res, next);
    expect(res.send).toBeCalledWith('success');
  });

  test('사용자를 못 찾으면 res.status(404).send(no user)를 호출함', async () => {
    User.findOne.mockReturnValue(null);
    await follow(req, res, next);
    expect(res.status).toBeCalledWith(404);
    expect(res.send).toBeCalledWith('no user');
  });

  test('DB에서 에러가 발생하면 next(error) 호출함', async () => {
    const message = 'DB에러';
    User.findOne.mockReturnValue(Promise.reject(message));
    await follow(req, res, next);
    expect(next).toBeCalledWith(message);
  });
});

image

실제 데이터베이스에 내용을 등록하는 것이 아니므로 실제 서비스의 실제 DB에서는 문제가 발생할 수 있으므로 유닛 테스트로는 한계가 있음 => 통합 테스트시스템 테스트

yellow-jam commented 8 months ago

3. 테스트 커버리지

package.json에서, jest --coverage 옵션: jest가 테스트 커버리지를 분석

"scripts": {
    "start": "nodemon app",
    "test": "jest",
    "coverage": "jest --coverage"
  },

image

File: 파일과 폴더 이름 % Stmt: 구문 비율 % Branch: if문 등의 분기점 비율 % Funcs: 함수 비율 % Lines: 코드 줄 수 비율 Uncovered Lines #s: 커버되지 않은 줄 위치

models/user.test.js 작성

image

yellow-jam commented 8 months ago

4. 통합 테스트

통합 테스트 준비

routes/auth.test.js 작성 - 로그인 라우터 테스트

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: 'zerohch0@gmail.com',
        nick: 'zerocho',
        password: 'nodejsbook',
      })
      .expect('Location', '/')
      .expect(302, done);
  });
});

describe('POST /join', () => {
  const agent = request.agent(app);
  beforeEach((done) => {
    agent
      .post('/auth/login')
      .send({
        email: 'zerohch0@gmail.com',
        password: 'nodejsbook',
      })
      .end(done);
  });

  test('이미 로그인했으면 redirect /', (done) => {
    const message = encodeURIComponent('로그인한 상태입니다.');
    agent
      .post('/auth/join')
      .send({
        email: 'zerohch0@gmail.com',
        nick: 'zerocho',
        password: 'nodejsbook',
      })
      .expect('Location', `/?error=${message}`)
      .expect(302, done);
  });
});

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

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

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

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

  const agent = request.agent(app);
  beforeEach((done) => {
    agent
      .post('/auth/login')
      .send({
        email: 'zerohch0@gmail.com',
        password: 'nodejsbook',
      })
      .end(done);
  });

  test('로그아웃 수행', (done) => {
    agent
      .get('/auth/logout')
      .expect('Location', `/`)
      .expect(302, done);
  });
});

//테스트 종료 시 데이터를 정리하는 코드 추가
afterAll(async () => {  
  await sequelize.sync({ force: true });
});
yellow-jam commented 8 months ago

5. 부하 테스트