지금까지 보통은, 개발을 하면서 API 구현를 구현하고 예외처리를 해왔었다. 값이 바뀌면 항상 서버를 돌리고, 포스트맨으로 값을 요청하고 전달받으며 테스트를 해왔었는데 사실 너무나도 비효율적이고 좋지 않은 테스트 방식이라는 것은 알고있었다. 하지만, 기능을 구현한다. 라는 문장에 집중된 개발 방식을 고집해오다보니 테스트 코드에 대한 중요성을 알고있으면서도 놓치고 있었다.
최근 지금까지 해왔던 코드를 리팩터링하면서, 새로운 코드가 정상 작동하는지에 대한 여부를 또 다시 포스트맨으로 고집한다는것에 대해 나에대한 환멸(...)을 느껴서 이번 기회를 삼아 테스트코드를 작성하고 좋은 테스트 코드를 만드는 법에 대해 알아보려 한다.
(기능을 구현한다) 라는 개발 방식이 아닌 TDD(test-driven development) 방식으로 개발 방식을 바꾸고 좋은 테스트와 더 넓은 관점에서 서비스를 구현할 수 있게끔 노력해보려 한다. 테스트 코드에 대한 포스팅은 이번편을 토대로 아마 몇개 더 작성할 예정이고, 해당 포스팅은 간단하게 개념적인 부분을 알아보려 한다.
만약, 우리에게 하나의 서비스화가 완료된 코드가 있다고 가정해보면 해당 코드를 테스트하는 사람이 있을 것 이다. 해당 기능과 관련없는 새로운 코드가 개발이 되었다 했을때, 분명 새로운 사람이 테스트를 진행하거나 기존의 사람이 테스트를 하나 더 해야한다.
근데 여기서 기존 서비스화된 코드를 공유하는 기능이 추가되었을때 새로 추가된 코드는 물론 기존 코드가 제대로 돌아가는지 확인을 해야한다. 즉, 기능과 관련이 없는 코드가 추가되어도, 공유가 되는 기능이 생겨도 테스트를 하는 인력과 비용은 증가한다. 특히 공유가 되는 기능은 기존 서비스에 영향을 줄 수 있기 때문에 위험하기도 하다.
간단히 정리해보자면
우리는 이제 테스트 코드를 왜 작성해야 하는지, 무엇을 놓치지 않는건지 알았기 때문에 테스트 코드를 꼭 작성해야 한다는 것은 알았다. 근데, 어떤 테스트 코드가 좋은 테스트 코드일까?
💡 수동적인 테스트가 아닌 자동화된 테스트 코드를 개발하자
@DisplayName("개발자 1명을 등록하면 유저 목록에 담긴다.")
@Test
void add_user_test() {
Site site = new site();
site.add(new developer());
System.out.println(" >>> 사이트 인원 수 : " + site.getUser().size());
System.out.println(" >>> 사이트 유저 : " + site.getUser().get(0).getName());
}
해당 코드는 유저를 등록하는 테스트 코드이다. 하지만, 해당 코드는 테스트에 대한 Log를 출력할 뿐, 결국 검증은 사람이 직접해야한다. 즉, 수동적인 테스트가 되기에, 이는 인력과 비용이 증가할 수 밖에 없기에 좋은 테스트 코드라고 볼 수 없다.
@DisplayName("유저 한명을 추가하면 사이트 목록에 유저가 추가된다.")
@Test
void add() {
Site site = new site();
site.add(new developer());
assertThat(site.getUser()).hasSize(1);
assertThat(site.getUser.get(0).getName()).isEqualTo("그릴리쉬");
}
해당 코드는 Juint5와 assertj를 이용해 테스트를 자동화시킨 코드이다. 즉 코드가 테스트를 한다. 사람이 직접 검증하지 않고 원하는 결과값이 제대로 도출되는지 코드가 검증을 하고 테스트를 통과하게 된다.
결국 자동화된 테스트코드를 작성하게되면 인력과 비용이 크게 증가할 일이 없어지고 코드가 코드를 검증하는 형태가 된다.
💻 단위 테스트를 진행하기
단위테스트란, 작은 코드 단위를 독립적으로 검증하는 테스트이다. 여기서 작은 코드 단위란 클래스, 메서드를 나타낸다고 볼 수 있다.
단위테스트로 테스트 코드를 작성하면 검증속도가 빠를 뿐만 아니라 정확하고 안정적인 테스트를 만들 수 있다.
😉 Junit5 & AssertJ 를 이용한 단위테스트
Junit5는 단위 테스트를 위한 테스트 프레임워크이다. 우리가 테스트 코드를 작성할때 단위 테스트는 물론 테스트를 위한 편의성도 증가시켜 준다
AssertJ는 테스트 코드 작성을 원할하게 돕는 테스크 라이브러리이다. 다양한 API를 지원함은 물론 메서드 체이닝을 지원하고 있다.
💪 테스트 케이스를 더욱 세분화 시키고, 경계값을 적극 활용하자 !
흔히 테스트라고 하면 해당 기능이 원하는 결과값을 도출하는지? 라고 생각할 수 있지만, 우리는 개발할때 예외처리를 한다. 즉, 어떠한 상황에서 해당 기능이 우리가 예상한대로 예외가 발생하는지에 대해 알아야 한다. 그렇기 때문에 우리는 테스트 케이스를 세분화 시킬 수 있다.
또한, 해피 케이스나 예외 케이스를 만들어 검증할때, 우리는 원하는 결과값을 지정하게 되는데 이때 검증이 되는 값을 경계값으로 지정하는 것이 좋다.
예를 들어 내가 사야하는 물건이 6000원일때 가진돈이 6000원 이하라면, 예외를 던지는 예외 케이스 테스트 코드를 작성한다고 하였을때 분명 4000원, 4500원과 같이 내가 가진 돈을 설정할 수 있지만, 5999원으로 설정해 기준이 되는 값의 경계값으로 지정하는 것 이다.
🥹 테스트하기 어려운 영역을 분리하자
이는 기능을 하는 코드에도 영향을 미칠 수 있다. 예를 들어, 내가 어떠한 기능을 작동하는 코드에서 내가 가진 돈의 기본값이 5999원 이라고 설정되어서 테스트코드에서 해당 기능을 테스트 한다하였을때, 우리는 6천원 이하일때 또는 이상일때를 테스트 하고 싶은거지 기본값을 테스트 하려 하는 것이 아니다.
즉, 기본적으로 값을 가지는 것이 아닌 클라이언트에서 기본값을 지정할 수 있게 만들어서 테스트 코드에서도 값을 생성하여 테스트를 할 수 있게끔 유연하게 구연하는 것 이다.
다음 포스팅에서는, TDD와 BDD를 알아보고 개인의 테스트 코드가 아닌 팀, 또는 전체의 인원이 쉽게 이해할 수 있는 테스트 코드를 작성하는 법에 대해 알아보자 😀