DataSource Test?

회사에서 DataSource 테스트 시스템을 구축할 일이 생겼다.
DataSource 테스트란 무엇일까?
DataSource 레이어에서는 어떤 테스트를 해야 할까?

만약 Repository 구현체의 테스트 코드를 작성한다고 가정하면, 실제 API를 호출해서 테스트하기엔 여러 문제가 있다. 테스트가 느려지고, 네트워크 환경에 따라 통신이 실패할 수도 있으며, DB의 데이터가 변경되면 테스트가 깨질 수도 있다. 게다가 테스트 요청이 POST라면? 실제 서버의 프로덕션 환경을 오염시킬 위험도 있다. (목업용 서버가 없다는 가정하에)
그렇다면 서버와 강결합된 상태에서 Repository 구현체의 테스트 코드를 작성하는 것이 과연 의미 있는 테스트일까?

  • 서버값을 검증하는 것은 서버에서 해야 하는 것 아닌가?
  • 서버 통신 자체를 검증하는 것은 네트워크 모듈에서 해야 하는 것 아닌가?

그렇다면 DataSource 레이어에서는 무엇을 테스트해야할까?

스스로(+AI와의 대화) 내린 결론은 협력자인 API Client 와의 상호작용과 역할 수행 여부를 테스트 해야 한다는 것이다.

  • 올바른 API Target으로 요청하는가?
  • 응답을 올바르게 매핑하고 위임하는가?
  • 실패 시 적절히 오류를 던지는가?
  • 사이드 이펙트 대응이 제대로 되어 있는가?

실제 테스트 구현은 URLProtocol을 채택해서 네트워크 호출 없이, URLSession 요청을 가로채어 요청/응답을 검증하는 방식으로 했다.
또한 정상 매핑, 서버 에러 전파, 디코딩 에러 전파가 올바르게 처리되는지 확인하고, 사이드 이펙트 검증에 대한 테스트도 추가하였다.

추가로 구축을 진행하면서 굉장히 많은 삽질을 했다.

의미있는 테스트 코드란 무엇인가
정말 말그대로 의미가 있어야 한다.
단순히 읽고 쓰기만 존재하는 코드에 테스트를 붙인다고 해서 과연 가치가 있을까?
예를 들어, API response를 model로 단순 매핑하는 동일한 구조의 코드가 여러 개 있다고 하자.
그 코드들에 전부 Unit Test를 붙이는 것이 과연 의미 있는 일일까?
테스트 코드를 구현할 때 버그를 사전에 잡고, Testability한 코드를 작성하는 것의 우선순위가 단순히 테스트 커버리지를 높이는 것보다 훨씬 높다고 생각한다.
즉, 의미 없는 테스트를 작성할 시간에 차라리 더 임팩트 있고 가치 있는 코드를 작성하는 편이
더 좋은 방향 아닐까? (물론 팀 상황에 따라 단순 테스트도 의미가 있을 수 있음!)

  • 의미 있는 테스트: 비즈니스 로직이 들어간 매핑, 사이드 이펙트, 실패 케이스, 에러 핸들링 등.
  • 의미 없는 테스트: 단순 boilerplate 매핑, Swift 자체 문법이 보장해주는 수준의 검증 등.

Testability한 코드란 무엇인가.

  • 컨벤션이 중요하다. 동일한 기능(API 추가 등)을 여러 개발자가 구현한다면, 모두가 같은 컨벤션으로 개발해야 한다. 그래야 AI도 이해할 수 있고, 테스트 코드 또한 동일한 DSL로 구현할 수 있다.
  • 목킹값, Spy, Stub과 같은 객체의 주입이 가능한 구조로 구현되어야 하며,
  • 재사용 가능한 구조 또한 가져야 한다.

자동화란 무엇인가.
개발자는 본질적으로 귀찮은 것을 싫어한다. 테스트 코드 작성 역시 같은 결(귀찮음)에 속한다.
정말 복잡하거나 개발자의 개입이 필요한 테스트가 아니라면, 테스트 작성은 지루한 일이 되기 쉽다.
이때 중요한 것이 자동화다. 위와 같은 테스트는 API 추가와 같은 주기로 통합되어야 귀찮음을 줄일 수 있다.
최근에는 AI가 문맥 파악과 구현을 잘하기 때문에, GitHub Action + AI를 활용해 개발 주기에 통합하는 것도 가능하다. (단, 과금 문제가 크지 않고 + 컨벤션과 템플릿화가 잘 되어 있어야 한다. 그래야 GitHub Action에 쉽게 붙일 수 있다.)