사실 Test가 중요하다는 것에 관해서는 누구나가 인지하는 점이다.
각 클래스, Layer들이 잘 작동하고 있는 것을 테스트하는 용도를 제외하고도, 다른 개발자들이 내 코드의 동작 방식에 대해서 이해하기 쉽게 만든다는 점 등 TDD는 필수가 되어가고 있다. 하지만 Framework와 여러 가지 패키징 된 라이브러리 등 테스트를 도와주는 여러 장치가 있음에도 여전히 테스트 코드를 작성하는데 생기는 시간, 노력이 많이 소요된다. 그렇다면 각각 컴포넌트들의 기능과 서로 의존성을 뛰는 컴포넌트들이 상호작용하며 잘 작동하는 알면서도 효율적으로 짤 수 있는 방법이 없을까?
AgileTeam의 Scott Ambler는 다음과 같이 말했다.
“구축 할 가치가 있다면 테스트 할 가치가 있습니다. 테스트 할 가치가 없다면 왜 시간을 낭비하고 있습니까?”
즉 효율성을 중요시했다. 생각해보면 Spring framework에서 지원하는 JPA의 경우나 기존에 구현을 완벽히 재현된 그러한 컴포넌트들에 대한 불필요한 테스트들의 관한 경우가 많았다.
Repository.save(model);
assert(Repository.findById(model.getId()).equals(model))
다음과 같은 코드들이 그러하다. 즉 테스트 코드를 작성할 때는 이러한 기존의 인터페이스에 관해서는 과감히 생략하고 오로지 우리가 작성한 코어로직 이자 비즈니스 로직에 관해서만 작성할 필요가 있는 것이다. 또한 우리는 SRP(단일 책임 원칙) 또한 테스트 코드에 녹여낼 필요가 있다. 왜냐하면 하나의 테스트 코드에 당장에 많은 기능에 대해 나타낼 필요는 없기 때문이다. 즉 Test 때마다 Spring의 모든 모듈에 관해서 부트스트랩 하지 말고 Mock을 과감히 적용시키는 게 좋아 보인다. 또한 여러 가지 다른 컴포넌트 및 유닛들이지만 비슷한 기능과 역할을 할 수 있다. 이것에 대해 전부 각각 다 만들기에는 정말로 비효율적이다. 가치가 없는 것들이다. 이런 것들에 대해서 AOP를 적용시켜 한 번에 처리하거나 몇 개의 대표적인 컴포넌트들에 관해서 샘플링을 해서 테스트하는 게 적절해 보인다. 요약하자면 다음과 같다.
- 코어로직, 비즈니스 로직 중심으로 테스트하기.
- 테스트코드에 SRP적용시키기 => Mock 과감히 적용시키기.
- 비슷한 기능들을 하는 컴포넌트에 대해서는 AOP를 적용시키거나 대표들만 테스트
그렇다면 각계층별로 어떻게 접근하는게 좋을까? 전체적으로 어떻게 관리하는게 좋을까?
먼저 계층별로 실제 도메인 및 클래스를 만들어서 사용하여 하는 경우가 많다. 이걸 그때그때 만들어야 하므로 굉장히 번거로운 작업일 수 있기에 전체 테스트에서 재사용할 수 있도록 펙토리 메서드 적용시키는게 좋아보인다.
Domain이 가지고 있는 getter()와 setter()를 테스트하기에는 너무나도 가치가 없다. 단 Domain들끼리 연관관계를 맺고 있는 경우에 이에 관해 연관관계 편의 메서드가 잘 작동하는지, 이러한 연관관계에 있는 도메인들이 영속성 컨텍스트에 persist 될 때 cascade로 인해 생기는 문제점은 없는지 정도를 테스트하면 된다.
사실상 Repository의 경우 Jpa에서 웬만한 기능을 전부 지원하기에 사용자가 구현한 CustomRepository, 예를 들면 QueryDsl repository 등에서 구현한 기능들에 대해서 테스트하면 된다. 이때는 실제 객체를 가지고 테스트하는 게 좋다.
Service의 경우에는 일반적으로 Repository를 가지고 그에 관한 값을 반환하거나 하는 Repository에서 구현한 것을 그대로 반환해 주는 메서드들이많다. 이에 대해 전부 구현해야 하는 게 맞을까? 또한 Service가 가지고 있는 비즈니스 로직 중 여러 service들이 공통으로 가지고 있는 구현한 기능들이 존재할 수 있다. 이것들에 대해서는 그 기능에 관한 테스트만 진행하면 되지 service를 통해서 테스트할 필요가 없다고 생각한다.
즉 해당 service 클래스에서만 독립적으로 사용자가 구현한 비즈니스 로직에 한해서만 테스트하면 된다고 생각한다.
Controller의 경우에는 Request에 따른 적절한 응답과 적절한 페이지 렌더링 및 값을 리턴하는지 테스트하면 되고 이에 관해서는 서비스와 마찬가지로 모든 계층의 기능들에 대해 담고 있을 필요가 없다. 따라서 MockMvc를 사용하여야 한다. 또한 필수는 아니지만 OSIV=True로 할 경우에 View 레벨에서 데이터가 예기치 못하게 변경되는지 정도를 테스트하면 될 것이다.
..