2020-8-18 Express, Supertest 환경분리

배경

  • 자바, 스프링에서 개발을 하다가 Express로 개발하면서 가장 어려웠던 부분은 테스트였다. 각 테스트가 끝나면 자동으로 종료가 잘 안됬다. 무엇보다도 개발데이터베이스와 테스트데이터베이스의 분리가 잘 안됬다 !!!

테스트코드

import {MongoMemoryServer} from 'mongodb-memory-server';

describe('Sample Test', () => {
  let mongoServer;
  beforeAll(async () => {
    mongoServer = new MongoMemoryServer();
    const URI = await mongoServer.getUri();
    await mongoose.connect(URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true
    }, () => {
      console.log(`success to memory db`)
    });
  });

  afterEach(async () => {
    const collections = await mongoose.connection.db.collections();
    for (let collection of collections)
      await collection.deleteMany();
  })

  afterAll(async (done) => {
    mongoose.disconnect(done)
  })

  test('회원 가입 테스트', async (done) => {
    request(app)
      .post('/users')
      .send({
        email: 'test@email.com',
        password: '123457',
        confirmPassword: '123457'
      })
      .expect(201)
      .end((err, res) => {
        if (err) return done(err);
        expect(res.body.email).toBe('test@email.com');
        done();
      })
  })
});
  • Describe단위로 testsuite를 분리했다. 여기서 beforeAll을 이용해서 처음 테스트가 실행될때, 몽고디비의 메모리서버를 구동시키고 mongoose를 이용해서 연결했다. JS문법이 익숙하지 않아서 mongoose와 db 커넥션을 맺는게 많이 헷갈렸다. 레퍼런스에도 다 mongodb와 직접적으로 커넥션을 맺고 있어서 더욱 힘들었다.
  • afterEach를 통해 각 테스트케이스가 완료되면 collections를 순회하면서 데이터를 초기화 한다.
  • afterAll에서 DB와 커넥션을 끊는다.

환경설정

// jest.config.js
module.exports = {
  preset: "@shelf/jest-mongodb",
  testEnvironment: "node",
}

// jest-mongdb-config.js
module.exports = {
  mongodbMemoryServerOptions: {
    binary: {
      version: '4.0.3',
      skipMD5: true
    },
    autoStart: false,
    instance: {
      db: 'test'
    }
  }
}
  • jest-mongodb-config파일에서 테스트에서 사용할 MongoMemoryServer에 대한 옵션을 설정한다. 지금은 테스트파일이 하나이지만 향후 여러개로 될때 공통속성으로 유용할거 같다.
  • 데이터베이스와 테스트간의 환경분리를 위해 jest옵션에서 preset을 지정한다. jest-mongodb를 사용하면 jest를 사용할때 미리 mongodb에 대한 설정을 한다고 간단하게 나와있다. 여기서도 teardown, global설정을 할 수 있는데, 아직은 적용하지 못했다. 추후 차근차근 분리를 시킬 예정이다.

그밖의 문제

  • 포트충돌 : 테스트 케이스를 여러개 돌릴때 포트충돌나는 경우가 발생했다. 원인을 찾아보니 jest에서 여러개를 돌리기때문에 –maxWorkers=1 옵션을 통해 한번에 1개만 돌아가도록 설정했다.
  • 테스트종료안됨 : 테스트가 종료되지 않고 계속 돌아갔다. –forceExit옵션을 통해 테스트가 끝나면 강제적으로 종료시켰다.

느낀점

  • 작년에도 Express를 하면서 Supertest와 express의 테스트환경 분리하는게 어려웠었다. 그때는 지금보다 시간적으로 해결하지 못해서 결국에는 testdb를 아예 따로 만들었었다. 오늘 작성한 코드에서는 테스트 데이터베이스를 분리할 수 있었다. jest옵션에 나온 global과 teardown옵션도 적용해봐야겠지만 추후 적용할 예정이다. 스프링에서는 test스코프와 일반 runtime 스코프에서 환경을 분리할 수 있고 테스트를 돌리기 쉬웠는데, node를 하면서 개념을 알지만 디버깅이나 코드로 녹여내는게 힘들었다. 하루종일 코드를 작성했다 지웠다를 반복하면서 다양한 생각들이 들었지만 그래도 큰 문제는 해결할 수 있었다.
Written on August 18, 2020