테스트 코드에 대한 나의 생각?

이상·2023년 4월 23일
0
post-thumbnail

ALL CODE IS GUILTY UNTIL PROBEN INNOCENT
검증되기 전까진 안전한 코드란 없다.
이미지 출처

시작하며


@Test
@DisplayName("유저를 등록한다.")
void UserCreateTest(){
  
  //given
  User user = new User("철수");
  
 //when
 userRepository.save(user);
 user DBUser  = userRepository.findByName("철수");
 
  //then
  assertThat(DBuser).isNotNull();
  assertThan(DBUser).isEqualTo(user);
}

위 테스트코드가 익숙하다면, 아마 이 글을 읽는 당신도 모 회사의 기술이사님의 강의를 들었지 않았을까?

Give, When,Then 의 기승전결을 가지고 있는 테스트코드
강의에서만 줄창 따라 적으며, 근데 이건 당연한거 아닌가?, 이정도의 로직도 검증이 필요하나?
라는 생각을 했던 어린 예전의 나에게 이 글을 바칩니다.

그때는 몰랐다, 아니 알았지만 느낀적 없었다.

앞서 언급한 것처럼 강의를 통해 접한 위 형식의 테스트 코드를 본 첫 감상은, 아 그냥 이렇게 해도 이거 잘 돌아가요, 이 기능 이렇게 하면 확인 됩니다. 를 보여주기 위한 강사님의 교육 방법이라고 생각했다.

웃기게도, 강의가 2주 조금 넘게 진행되고 있는 지금도 테스트코드를 왜 짜야하는지? 에 대한 질문의 대답은 위 문장과 같다. 이 기능 잘 동작합니다. 거기에 하나가 더 추가된 게 있다면 이렇게 하면 이런 에러가 납니다. 정도일까?

내 안에 테스트 코드의 존재 의미는 변함이 없지만 대하는 태도가 크게 바뀐 계기가 있다.
요근래 업무를 하며 크게 느낀 불편함에 대한 부분이었는데

테스트코드가 없는 환경의 불편함을 처음 느낀 건

유지보수를 중점적으로 하는 SI 회사에 재직중인 나의 업무중
큰 비중을 차지하는 것은 클라이언트의 요구에 따라 API 의 규격을 약간 손봐야하는 경우 이다.

이는 단순히 유지보수가 아닌 회사에서 맡은 자체 솔루션 개발 중에도 자주 생긴다.
개발된 API를 약간 수정해주세요. 필드를 좀 바꿔 주세요. 이거 DB 규격을 ~게 바꿨어요.

아니, 이는 나에 국한된 것이 아니라 모든 개발자들에게 해당되는 사항이라고 감히 생각할 수 있다.

즉, 이미 개발된 기능에 영향을 줄 수 있는 변화가 생겼을 때 또는 바꿔야할 때, 주변에서 가장 많이 듣는 얘기는 이거 개발전에, 어디 다른 곳에서 쓰는지, 확인해야돼요. 이다.

당연한 말이 아닐 수 없다, 내가 바꾼 경로 우대 할인(30%) 정책의 필드값 때문에 기존의 할인을 받던 국가 유공자 할인(50%)의 대상자가 30% 추가 할인을 받는다고 생각해보자.
(더 멀끔한 예시가 있을텐데, 필력의 한계인 것 같다.)

그런데, 그게 쉽지 않다.
이미, 서비스가 오래 지속된 코드의 메인로직의 경우,
1. 이를 참조하는 모든 코드를 파악하는데 드는 시간만해도 무시할 수 없다.
2. 생길 수 있는 사이드 이펙트를 그때 그때 확인한다고 해도 100% 로 무결한 코드를 만든다는 보장이 없다.
3. 당시엔 발견되지 않은 문제가 나중에 큰 재앙으로 다가올 수 있다.(정말로)

테스트 하자! 특히 중요한 비즈니스 로직은

이미 돌아가고 있는 Payment 의 pay 메서드에
내가 나이 50 이상인 사람들을 위한 경로 우대 할인기능을 개발했다.
(물론, 할인의 경우, User 안의 타입 Field로 분간하는것이 더 좋은 방법일거다.)

public class PaymentService{

public Payment pay(int price, User user){
      ...

      if(user.getAge() >50){
          price *= 0.7;
      }
      
      ...
  }

}

이제 딱봐도 문제가 될 확률이 매우 높아보이는 코드를 작성한 금요일 난 퇴근했다.
그리고 그 다음날, 국가 유공자 단체에서 100 명의 단체손님이 이 서비스를 예약했고,
그중 50% 가 50세 이상의 노인
이었다면?

편안한 주말을 보낼 수 있었을까?

만약 방금 적은 사례의 테스트코드가 있다고 생각해보자.


public class PaymentTest{
  @Test
  @DisplayName("국가 유공자는 할인을 받아요. 50%")
  void worshipSaleTest(){

  //given
  User user  = User.Builder().
                  .name("할아버지")
                  .age(80)
                  .SaleType(SOLDIER) // 군 할인 적용( 국가 유공자 중 하나)
                  .build();
  private int price = 10000;

  //when
  paymentService.pay(price, user);


  //then
  Payment pay = paymentService.findCurrentPayByUser(user);
  Assertion.assertThat(pay.getPrice()).isEqualTo(5000);
  }
}

이런식으로 테스트 코드를 짤 수 있을 거다.

그리고 우리 회사엔 개발 배포 전 Jenkins 가 Build 를 하며, 중요로직인 Payment 테스트의 커버리지가 100% 가 되지 않으면, 배포를 하지 못하게 막아 놓았다고 가정해보자.

적어도, 금요일 퇴근을 재때에 못할지라도 다음주 월요일날 우울한 생각과 함께 출근하진 않았을 거다.

문제가 터지고, 느끼면 너무 늦는다.

마무리

토스ㅣSLASH 21 - 테스트 커버리지 100%

최근에 테스트 코드에 대해 검색하다. 위 영상을 되게 감명깊게 봤다.
토스 같은 큰 도메인에서도 실현한 일을 모든 기능이 아닌 최소한 주요 비즈니스 로직은 모두 커버할 수 있는 테스트 코드를 짜는 것이 과연 불가능한 일일까?

주요 비즈니스 레벨의 테스트 코드는 옵션이 아닌 필수 라고 생각된다.

그리고, 해당 어플리케이션이 테스트 커버리지가 완벽하다는 자신이 있다면 더 이상 주요로직을 손볼때마다 어떤 api 가 바뀌는 로직에 영향을 받을지 처음부터 끝까지 추적하며 개발하는 시간낭비가 사라지지 않을까?

반복되는 일을 줄이고, 시간낭비를 줄이는 것이 개발자의 미덕 인데,
이걸 제대로 배워서 나의 시간을 아끼는 것에 열과 성을 다하는 것은 당연한 것이 아닐까?

profile
더 잘 하고 싶은 개발자

0개의 댓글