보다 효율적인/효과적인 테스트 작성

도툐리 2024. 2. 22. 23:47

1. 테스트 관련 이론 개괄

1-1. 개발할때 테스트 작성을 하는 이유

1-1.(1) from 안드로이드 문서

  • 장애에 관한 신속한 피드백
  • 개발 주기에서 조기 장애 감지
  • 회귀에 신경 쓸 필요 없이 코드를 최적화할 수 있도록 하는 더 안전한 코드 리팩터링
  • 기술적 문제를 최소화하는 안정적인 개발 속도

1-1.(2) from 🐇💬

  • 기획자의 의도 세분화
  • 새로 추가한 테스트 단위로 PR을 올리게 되면 협업 시 각자의 작업 내용을 이해하기 쉬워짐.
    • 자신이 작업하지 않은 부분이어도 코드 구현 내용 및 과정을 보다 더 잘 이해할 수 있게 됨.
      -> 양질의 리뷰를 받을 수 있게 됨.
  • 수동 리그레션 테스트에 드는 비용을 유의미하게 줄일 수 있음.
    • 요건 서비스 규모가 커질수록 더욱 큰 효용을 지닐것.
  • 번거로운 환경 세팅 작업들이 반복적으로 필요한 수동 테스트에 드는 비용을 유의미하게 줄일 수 있음.
    • (ex) fromm fan-app의 경우 로그아웃이 없기 때문에 로그아웃하고 다시 로그인하는 작업을 테스트 하고 싶은 경우 앱을 지우고 다시 받거나 앱 설정 페이지로 가서 데이터를 날려주고 다시 앱으로 돌아와 확인해야하는 등 그 과정이 번거로움. 특히 이 과정을 반복해야하는 경우 테스터의 피로감이 누적될것임. 시간도 많이 걸리고. 이 부분을 테스트코드로 작성해 처리하면, 반복적으로 이런 번거로운 작업을 할 필요가 없어짐.

1-1.(3) from 리팩토링 2판 - 4장 : 테스트 구축하기

 

 

1-2. 테스트 종류

(출처 링크)

 

  • Unit tests (or small tests)
    • → only verify a very small portion of the app, such as a method or class.
    • 하나의 클래스의 동작의 유효성을 검사하는 단위 테스트이다.
    • 단위 테스트란 애플리케이션을 구성하는 작은 단위의 기능이 개발자가 의도한 대로 동작 하는지 확인하는 테스트이다.
    • 단위 테스트를 통해 기능에서 발생하는 문제를 빠르게 찾을 수 있다.
  • Integration tests (or Medium tests)
    • → are in between and check the integration between two or more units.
    • 모듈간의 상호작용의 유효성을 검사하는 통합 테스트이다.
    • 통합 테스트는 단위 테스트가 끝난 모듈을 통합하는 과정에서 발생하는 오류, 결함 찾는 테스트이다.
    • 🐇💬: “컴포넌트 테스트도 integration test에서 진행한다”
  • End-to-end tests (or big tests)
    • → verify larger parts of the app at the same time, such as a whole screen or user flow.
    • 사용자의 경험에 대한 유효성을 검사하는 e2e테스트이다.
    • e2e테스트는 사용자의 입장에서 애플리케이션을 테스트하는 것이다.

 

* 비중? 우선순위?
small → big test로 갈수록 테스트를 수행하는데 드는 비용이 증가한다. 
따라서 안드로이드 문서에서는 small부터 시작해 
small-70, medium-20, big-10의 비율로 테스트 코드를 작성하는 것을 권하고 있다.

 

 

* 안드로이드 프로젝트 내 각 테스트를 수행하는 폴더 위치는?

  • androidTest :
    • 실제 또는 가상 기기에서 실행되는 테스트가 포함된다.
    • 통합 테스트, e2e 테스트등 jvm만으로 애플리케이션의 유효성을 검사할 수 없는 테스트가 포함된다.
  • test :
    • 유닛 테스트와 같이 로컬 시스템에서 수행되는 테스트를 포함한다.

 

* 현재 프론트 팀에서는 테스트 관련 내용을 어떻게 PR에서 강제하고 있을까?

  • PR 템플릿에 아예 테스트케이스 작성 항목이 있음.
  • 설령 해당 작업 관련 테스트 코드가 없다 하더라도, PR에서 무조건 테스트 케이스를 작업자가 직접 작성하는 구조인것으로 파악됨.
  • (ex) 

 

 

 

2. 테스트 도입 관련 내용검토

2-1.  프로젝트에 테스트 도입이 필요하다고 생각되는 이유

사실 테스트 코드를 작성하는것 자체도 중요하지만, 그에 앞서

 

[1] 테스트케이스를 구체적으로 그리며 기능구현을 하는것,

(요게 내 머릿속에만 그려지는게 아니라 동료들에게도 공유되어야함)

 

[2] 테스트 가능성을 고려하며 코드를 짜는것

  • (응집도 ↑ 결합도 ↓)

참고 from : (링크)

: (2번 - DB나 API 같은 외부 의존성이나 부수효과를 일으키지 않는, 순수한 도메인 로직)

 

[1], [2] 요 두가지가 더 중요하다고 생각함.

 

 


  • 테스트를 잘짜려면 수동테스트부터 “잘” 할 줄 알아야 한다.
    • 기획서 나오면 테스트코드 작성과 별개로 각 스펙을 GIVEN, WHEN, THEN으로 “잘” 나눠 테스트케이스를 작성할 수 있어야 한다. → BDD
      • GIVEN : 전제조건 (상태, 외부의존성)
      • WHEN : 동작
      • THEN : 후행조건 (부수효과 포함)

함수형 코드가 테스트하기 용이한 이유?

  • 함수형 코드는 보통 외부 의존성이나 부수효과를 멀리하기 때문에 복잡한 의존성 setup을 하지 않아도 테스트를 할 수 있음.
  • 특히 시간이나 랜덤이나 외부에서 들어오는 데이터 같은 건 매번 바뀌니까 테스트하기가 어려운데 순수 함수는 같은 입력이 들어가면 매번 같은 출력이 나오니까 테스트하기 쉬운 면이 있음.

 

질문 :

“그럼 항상 클래스 대신 함수로 작성하는게 테스트하기 좋겠네요?”

답변:

“🙅 function을 쓰고, class를 쓰고 하는 차원의 문제가 아닙니다!”

  • class를 쓰더라도 객체지향적으로 모델링을 하지 않으면 객체지향이라 하기 어려움.
  • 또, 함수형 프로그래밍이 꼭 함수만 쓴다는것도 아님.
    • 불변 객체나 final이 많은 클래스는 순수 함수처럼 테스트하기 쉬운 경우가 많음.
    • 반면에 함수라 해도 안에서 set이나 = 할당이나 push, append, remove 같은 부수효과를 남용하면 함수적이지 않음.
  • 한편, 꼭 class 형태로 작성해야만 하는 애들도 있음.
    • 예를 들어 DB나 서버나 사용자 같은 건 외부에 있으니까 이런 상태는 함수형으로 모델링하기가 어려움.
    • 그래서 외부 의존성을 보통 객체로 감싸서 씀.
  • 따라서, 어떤 패러다임이 중요하다기 보다는 불변이나 응집도나 테스트하기 쉬운 코드 같은 걸 염두에 두고 저런 패러다임의 방법을 가져다 적용해보면 더 좋을 것 같음.
  • "이건 함수형 스럽지 않네?" 보다는 "이건 로직이 이것저것 뒤섞여있네? 어떻게 해야 응집도 있게 나눌 수 있을까?" 를 생각!

 


 

<참고용 링크 모음> 

- mocking 에 대한 의문점 해소에 도움이 된 태희님 글
함수형 프론트엔드에서 의존성 제어하기 : Wonderwall Tech 

- 모바일 (AOS,IOS 모두 적용) UI 테스트에 활용하기 좋은 테스팅 툴
https://maestro.mobile.dev 

테스트하기 좋은 코드란?
1. 테스트하기 좋은 코드 - 테스트하기 어려운 코드 
2. 테스트하기 좋은 코드 - 제어할 수 없는 코드 개선 
3. 테스트하기 좋은 코드 - 외부에 의존하는 코드 개선 
4. 테스트하기 좋은 코드 - 검증이 필요한 비공개 함수