테스트 코드에 대한 중요성을 알고 이를 작성해나가고 있지만 원칙을 정하기가 어려운와중에 스프링 캠프에서 권용근님의 무엇을 테스트할 것인가? 어떻게 테스트할 것인가에 대한 발표 영상을 보게되었다. 아래 포스팅은 발표 영상을 요약한 내용이다. 테스트에 대한 기본 원칙을 세우고 싶으시다면 맨 아래 REFERENCE의 동영상 주소를 참고하면 된다.

 

1. 무엇을 테스트할 것 인가?

예를 들면 로또 시스템을 개발한다고 생각해보자. 그렇다면 요구 사항을 정리한다면 다음과 같다.

 

  • 6개의 숫자 반환
  • 중복되지 않은 숫자
  • 랜덤하게 반환

 

중복되지 않은 숫자 테스트는 안해도 되는가??

 

-> 구현은 언젠가 변할 수 있다라는 것을 명심해야한다.

 

 

private 메소드인 actD는 어떻게 테스트할 것 인가??

 

테스트 케이스를 추가해서 actC()를 테스트한다.

설계를 했던 사항 그대로 테스트 코드로 옮겨져서 테스트되야한다.

 

원칙 1 : 구현이아닌 설계를 테스트해야한다.

 

원칙 2 : 테스트 가능한 것. 불가능한 것

콜트리를 보면 맨 아래 테스트할 수 없는 메소드가 있다면 전체가 테스트할 수 없게 물들어진다.

  • 제어할 수 없는 영역
    • random 메소드, Shuffle, LocalDate.now()
    • 외부 세계
      • HTTP
      • 외부 저장소

즉, 랜덤하게 반환은 테스트가 불가능 하므로 다르게 풀어서 테스트할 수 있게 만들었어야함.

테스트할 수 없는 메소드를 Boundary 영역까지 끌어올리면 테스트할 수 있는 영역을 많이 확보할 수 있다. 

 

isValid가 LocalDateTime.now()를 사용하고 있기 때문에 테스트할 수 없는 영역이었다.

 

파라미터로 받을 수 있게 바꾸면서 테스트할 수 있는 영역을 점점 끌어올릴 수 있다. 이렇게 테스트할 수 있는 영역을 많이 늘릴 수 있다.

 

2. 어떻게 테스트할 것 인가?

@SpringBootTest를 사용해서 테스트하면 무척 편하게 테스트가 가능하다.

하지만 스프링을 사용하고 있다고 꼭 스프링 컨텍스트를 사용해야할지 고민이 필요하다.

Spring Context를 사용하면 느리다. 따라서 빠른 피드백을 받을 수 없다.

 

자바 개발자인지 스프링 프레임워크 위에서만 돌아갈 수 있는 개발자인지 생각이 필요함.

 

원칙 3 : Context, Framework에 종속적이지 않은 테스트를 우선

 

3. Test Double

테스트할 수 없는 영역에 대한 외부 요인을 부여할 수 있도록 도와주는 도구.

자바에서는 "mockito"가 이런 도구에 해당

 

그렇다면 무엇을 Test Double로 처리할것인가?

 

4번만 테스트할 때 1,2,3은 기대한 값으로 반환하게한다는 것은 결국 1,2,3의 구현을 알아야한다. 2번쪽의 반환 타입을 변경하거나 3번의 입력 값을 변경하면 테스트가 계속 깨짐. 실제 코드 보다 테스트 코드 수정하는게 더 힘들어지는 상황이 발생한다.

 

Boundary Context까지 끌어올려졌을 때 더이상 테스트할 수 없는 영역이 있을 때 그거에 대한 통합 테스트를 이끌어 내야할 때 사용. 그렇지 않은 경우에는 2,3번도 하나의 의미를 갖는 모듈일 때 충분히 테스트되고 검증되서 올라온 애들이라서 돌아가도 된다.

 

순수 자바 어플리케이션으로 테스트할 수 없는것

  • 저장소에 대한 입출력 검증 (쿼리가 잘 나갔는지)
  • SPEC 검증
    • 내부 Controller
    • 외부 API

 

4. Embedded

이런 임베디드 시스템을 사용하면 제어할 수 없는 영역을 제어 가능하도록 만들 수 있음. 너무 남용하면 안좋음.

 

 

 

임베디드 시스템은 라이브러리 버전이라든지 대응속도가 느려서 따라가는게 느림.

 

5. End Point 테스트

 

컨트롤러를 테스트하려면 그 안에 있는 비즈니스를 다 알아야함. 

 

뒤에를 모르게해서 요청과 응답만 검증한다는 전제를 깔고하는게 좋다. 모든 케이스를 다 고려하는건 너무 힘듬.

 

Spring REST Docs를 사용하면 테스트를하면서 문서를 만들 수 있다.

 

6. Spring Cloud Contract

 

 

테스트 케이스가 자동으로 뽑아짐. 테스트한게 빌드하면 jar로 만들어서 어디에 올릴 수 있음. 

 

실행가능한 jar이기 때문에 띄울 수 있음. @AutoConfigureStubRunner를 통해서 테스트할 수 있음. 혼자하기는 힘들고 개발팀의 긴밀한 협력이 필요.

7. 테스트 상호 독립

테스트는 상호 독립적으로 작성을 해야한다. 테스트 1번에서 삽입하고, 테스트 2번에서 수정하는식으로 작동하면 안된다.

 

모든 테스트의 순서와 관계를 생각하며 테스트를 작성하기 어렵다.

 

임베디드 시스템을 사용해도 똑같음. 테스트마다 독립적으로 실행되야한다. 저장소를 공유하긴하지만 테스트가 끝나고 지워주는 룰같은 것을 두고 하면 좋다.

 

테스트 순서가 필요하면 JUnit5의 DynamicTest를 통해서 하나의 라이프 사이클에서 돌아가도록 수행한다.

 

8. 테스트 안에 의도와 목적이 드러나도록 작성한다.

누군가가 테스트 코드만 봐도 비즈니스의 플로우를 파악할 수 있어야한다.

9. 테스트 코드도 리팩토링 대상이다.

코드의 양이 늘어가면서 가독, 안정성, 요구사항 정리 등 비즈니스 코드와 동일한 수준의 리팩토링이 함께 이루어져야한다.

 

최종 정리

 

REFERENCE

https://www.youtube.com/watch?v=YdtknE_yPk4&ab_channel=springcamp.io 

'Test' 카테고리의 다른 글

코드 커버리지 적용(1) - 커버리지란?  (0) 2021.11.30
Mockito && 스프링부트 테스트 관련 어노테이션 정리  (0) 2021.11.17
단위 테스트(Unit Test)  (0) 2021.11.17
테스트 종류  (0) 2021.11.17
AssertJ 기본 사용법  (0) 2021.11.15
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기