728x90

https://springdream0406.tistory.com/224

 

Test Code 2

통합테스트 코드를 작성해본 후, 대부분을 mock으로 처리해놓은 현재 유닛테스트에 대한 의문을 가지고 있던 중, https://tech.inflab.com/20230404-test-code/ 테스트 코드를 왜 그리고 어떻게 작성해야 할

springdream0406.tistory.com

에 이어진 글로 테스트코드를 변경한 점에 대한 내용이다.


MockData

우선은 MockData에 대해서 얘기해보자.

테스트 코드를 개선하기 전에 unit test는 전부 mocking을 해서 테스트했다.

그러다보니 당연히 테스트에 사용할 매개변수와 return 되는 값들을 만들어줘야 했다.

 

처음에는 이런것들 중 공통적으로 사용되고 변경이 안될 데이터들을 다른 파일에 모아서 만들고 이를 가져다가 사용했다.

하지만 테스트의 독립성과 목적등에 대해 생각하고 코드를 변경하면서 이것도 여러번 변경을 했다.

 

우선 이들을 한데 묶어서 사용하기 편하게 만들고 독립성을 위해 클래스로 만들었다.

하지만 나는 기능을 한 클래스에 묶어놓고 이를 가져다 쓰고 싶었는데 기능을 사용할때마다 new 처리를 해줘야한다는 점이 너무 불편했다.

(함수로는 1줄로 끝날 코드가 new로 인해 무조건 2줄 이상이 되어버렸다.)

 

그래서 이를 다시 return 함수들로 만든 후 객체로 묶었다.

export const TestMockData = {
  deleteResult({ raw = [], affected = 1 }: MDIDeleteResult): DeleteResult {
    return { raw, affected };
  },

  updateResult({
    generatedMaps = [],
    raw = [],
    affected = 1,
  }: MDIUpdateResult): UpdateResult {
    return {
      generatedMaps,
      raw,
      affected,
    };
  },
}

대충 위와 같은 모습으로 딱히 상태관리할게 없다고 판단하여  함수로 만들었으며, return 처리해서 모든 생성된 데이터들의 독립성을 확보했다.

 

하지만 db에 데이터를 넣는 방법의 경우 class로 만들었다.

우선 초기 코드는 db에 넣을 데이터를 만드는 함수로 데이터를 만들고, 이를 레퍼지토리에 일일이 넣는 코드를 각 테스트마다 구현했었다.

 

당연히 귀찮은 일이라 db에 넣을 데이터를 만드는 함수를 객체로 묶고 레퍼지토리를 주입받아서 db 저장까지 이루어지는 함수를 만들었다.

하지만 db를 pg-mem으로 변경하면서 db를 구현하는 방법이 달라졌고, 각 테스트마다 생성한 dataSource로 만드는 repository들이 충돌을 일으키게 된다.

 

이를 해결하기 위해 entityManager를 사용하게 되고, 모든 함수가 entityManager를 넘겨받아 사용하게되자 이를 class로 변경하여 생성시 주입받고 상태를 유지하도록 변경했다.

export class DBDataFactory {
  constructor(private readonly entityManager: EntityManager) {}

  createUsers(xList: number[]): User[] {
    return xList.map((x) =>
      this.entityManager.create(User, {
        kWh: 100,
        recWeight: 1,
        businessNumber: `12345678${x}`,
        address: 'mockAddress',
        role: Role.USER,
      }),
    );
  }
  
  async insertUsers(xList: number[]): Promise<User[]> {
    const users = this.createUsers(xList);
    await this.entityManager.insert(User, users);
    return users;
  }
}

대충 위와 같은 모습으로 만들어서 db에 넣을 데이터를 생성하거나 바로 db에 넣도록 만들었다.

 

위의 두 변경으로 인해 테스트 간의 독립성을 위해 테스트마다 생성하던 데이터를 쉽게 생성하도록 만들었다.


pg-mem

https://springdream0406.tistory.com/225

 

pg-mem Nest에 Test DB로 설정하기

pg-mem을 Nest 프로젝트의 Test DB로 적용하기로 한 이유https://springdream0406.tistory.com/224 Test Code 2 (작성 중)통합테스트 코드를 작성해본 후, 대부분을 mock으로 처리해놓은 현재 유닛테스트에 대한 의

springdream0406.tistory.com

적용방법등은 위 글을 참조.

 

기존 e2e 테스트의 경우 db충돌로 인해 test 명령어에 --runInBand를 적어서 순차적으로 진행했는데, pg-mem으로 변경하면서 각 테스트마다 db를 생성해서 사용하니 다시 병렬적으로 테스트 진행이 가능해졌다.

pg-mem으로 변경하니 속도는 당연히 빨라졌는데, 내 맥북의 문제인지 아니면 코드의 문제인지 --runInBand의 경우 썼을 때와 안썼을 때 둘의 차이가 거의 없다. 오히려 --runInBand가 더 빠르기도 하다..

무튼 Test Suites 13 / Tests 118 기준, 3.988s => 3.062s 로 약 23% 개선되긴 했다.


코드

최종적으로 테스트 코드의 개선이다.

우선 로직이 작성한데로 돌아가는지 중간중간에 작동해야되는 함수들의 작동여부를 체크하던 mocking 위주의 테스트에서 결과 중심적인 테스트로 변경을 했고 덕분에 코드가 많이 줄었다.

그리고 given, when, then 주석을 통해 코드를 분리해주면서 가독성을 높였고, 코드를 수정하면서 가독성에 신경을 쓰기위해 노력했다.

 

현재 내 코드의 특성상 대부분이 db와 관계되어있어서 mocking을 줄이니 유닛테스트로 처리할 부분이 거의없어서 controller를 빼곤 거의 전부 통합테스트 코드로 변경되었다.

근데 mocking들을 없애버려서 그런지 의존성 주입된 줄들이 Uncovered Line으로 노란색 표시가 된다..

 

며칠동안 테스트코드 적용하고 개선한다고 고생했다..ㅎㅎ

728x90

'코딩 > 생각&후기&기록' 카테고리의 다른 글

프로젝트 글의 구성 변경  (0) 2024.12.09
yarn v1 => pnpm  (0) 2024.11.22
Test Code 2 - 개선생각과 방향  (0) 2024.11.15
Test Code - 좋은 점  (0) 2024.11.14
if문 한줄의 중괄호 생략  (1) 2024.11.02

+ Recent posts