Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

eumjo_o

Unit Testing 6장 본문

카테고리 없음

Unit Testing 6장

eumjo_o 2023. 6. 30. 18:34

6장 단위 테스트 스타일

6.1 단위 테스트의 세 가지 스타일

  • 출력 기반 테스트 output based testing
  • 상태 기반 테스트 state based testing
  • 통신 기반 테스트 communication based testing

6.1.1 출력 기반 테스트 정의

💡 출력 기반 테스트 output based testing 테스트 대상 시스템(SUT)에 입력을 넣고 생성되는 출력을 점검하는 방식

 

  • 전역 상태나 내부 상태를 변경하지 않는 코드에만 적용되므로 반환 값만 검증하면 됨
  • 이러한 테스트 스타일은 부작용이 없고, SUT 작업 결과는 호출자에게 반환하는 값 뿐

⇒ 함수형 프로그래밍 functional programming

6.1.2 상태 기반 스타일 정의

 💡 상태 기반 테스트 state based testing 작업이 완료된 후 시스템 최종 상태를 확인하는 것 상태: SUT, 협력자 중 하나, 데이터베이스, 파일 시스템 등과 같은 프로세스 외부 의존성의 상태 등

 

6.1.3 통신 기반 스타일 정의

💡 통신 기반 테스트 communication based testing 목을 사용해 테스트 대상 시스템과 협력자 간의 통신을 검증 : SUT의 협력자를 목으로 대체하고, SUT가 협력자를 올바르게 호출하는지 검증

 

  • 고전파 - 상태 기반 스타일 선호
  • 런던파 - 통신 기반 스타일 선호
  • ⇒ 두 분파 모두 출력 기반 테스트 사용

6.2 단위 테스트 스타일 비교

  • 회귀 방지
  • 리팩터링 내성
  • 빠른 피드백
  • 유지 보수성

6.2.1 회귀 방지와 피드백 속도 지표로 스타일 비교하기

회귀 방지 지표 결정 요인

  1. 테스트 중에 실행되는 코드의 양
  2. 코드 복잡도
  3. 도메인 유의성

6.2.2 리팩터링 내성 지표로 스타일 비교하기

 💡 리팩터링 내성 - 리팩터링 중에 발생하는 거짓 양성(허위 경보) 수에 대한 척도

 

  • 출력 기반 테스트가 테스트 품질이 좋다.
    • 구현 세부 사항에 거의 결합되지 않으므로 리팩터링 내성이 있고,
    • 작고 간결하므로 유지 보수하기도 좋다.

6.2.3 유지 보수성 지표로 스타일 비교하기

  • 상태 기반 테스트
    • 비공개 상태를 노출하지 않도록 해야 한다.
    • 출력 기반 테스트보다 크기가 커서 유지 보수가 쉽지 않다.
    • 헬퍼 메서드와 값 객체를 사용해 유지 보수성 문제를 완화할 수 있지만 제거할 수는 없다.
  • 통신 기반 테스트
    • 애플리케이션 경계를 넘어서 외부 환경에 부작용이 보이는 통신만 확인해야 한다
    • 통신 기반 테스트의 유지 보수성은 출력 기반 테스트 및 상태 기반 테스트와 비교할 때 좋지 않다
    • 목은 공간을 많이 차지하는 경향이 있어서 테스트 가독성이 떨어진다

6.2.4 스타일 비교하기: 결론

출력 기반 상태 기반 통신 기반

리팩터링 내성을 지키기 위해 필요한 노력 낮음 중간 중간
유지비 낮음 중간 높음

6.3 함수형 아키텍처 이해

6.3.1 함수형 프로그래밍이란?

💡 함수형 프로그래밍 - 수학적 함수로 된 프로그래밍

 

수학적 함수 - 숨은 입출력이 없는 함수(메서드)

  • 하나의 입력, 하나의 출력, method signature
  • 수학에서의 함수 예 - f(x) = x+1
public int Increment(int x) {
	return x + 1;
}

int y = Increment(4);
int y = 5; // 동일한 구문임.
  • 테스트가 짧고 간결, 유지 보수에 쉬우며, 거짓 양성 빈도 낮음
  • 부작용과 예외가 숨은 출력에 해당한다
    • 부작용 - 메서드 시그니처에 표시되지 않은 출력
    int x = 0; // x의 변경 -> 부작용 -> 숨은 출력
    public int Increment() {
    	x++;
    	return x;
    }
    
    • 내외부 상태에 대한 참조 - DateTime.Now, 데이터베이스 등

6.3.2 함수형 아키텍처란?

  • 함수형 프로그래밍의 목표
    • 부작용을 완전히 없애는 것이 아니라 비즈니스 로직을 처리하는 코드와 부작용을 일으키는 코드를 분리하는 것
    • 결정을 내리는 코드와 해당 결정에 따라 작용하는 코드 유형을 구분해서 비즈니스 로직을 처리하는 코드와 부작용을 일으키는 코드를 분리가능하다.
    • 두 계층을 잘 분리하려면, 가변 셀이 의사 결정을 추가하지 않게끔 결정을 나타내는 클래스에 정보가 충분히 있는지 확인해야 한다.
    • 목표는 출력 기반 테스트로 함수형 코어를 두루 다루고 가변 셀을 훨씬 더 적은 수의 통합 테스트에 맡기는 것
  • 함수형 아키텍처
    • 부작용을 다루는 코드를 최소화하면서 순수 함수(불변) 방식으로 작성한 코드의 양을 극대화한다.
    결정을 내리는 코드 - 수학적 함수를 사용해 구현됨, 함수형 코어(functional core) == 불변 코어(immutable core)
    • 가변 셀은 모든 입력을 수집
    • 함수형 코어는 결정을 생성
    • 셀은 결정을 부작용으로 변환
  • 해당 결정을 따라 작용하는 코드 - 함수형 코어에 입력 데이터를 제공하고 데이터베이스와 같은 프로세스 외부 의존성에 부작용을 적용해 그 결정을 해석, 가변 셀(mutable shell)

 💡 캡술화와 불변성 소프트웨어 프로젝트의 지속적인 성장을 가능하게 하는 것

객체지향 프로그래밍은 작동 부분을 캡슐화해 코드를 이해할 수 있게 한다. 함수형 프로그래밍은 작동 부분을 최소화해 코드를 이해할 수 있게 한다.

 

6.3.3 함수형 아키텍처와 육각형 아키텍쳐 비교

  • 함수형 아키텍처
    • 모든 부작용을 도메인 계층 밖으로 밀어낸다.
  • 함수형 아키텍처는 모든 코드를 함수형 코어와 가변 셀이라는 두 가지 범주로 나눈다.
    • 가변 셀은 입력 데이터를 함수형 코어에 공급하고, 코어가 내린 결정을 부작용으로 변환한다.
  • 육각형 아키텍처
    • 결정과 실행을 분리하는 함수형 아키텍처와 매우 유사.
    • 도메인 계층과 애플리케이션 서비스 계층을 구별한다.
    • 도메인 계층은 비지니스 로직에 책임이 있는 반면, 애플리케이션 서비스 계층은 데이터베이스나 SMTP 서비스와 같이 외부 애플리케이션과의 통신에 책임이 있다.

6.4 함수형 아키텍쳐와 출력 기반 테스트로의 전환

함수형 아키텍처로 리팩터링하는 두 단계

  • 프로세스 외부 의존성에서 목으로 변경
  • 목에서 함수형 아키텍처로 변경

6.4.1 감사 시스템 소개

6.4.2 테스트를 파일 시스템에서 분리하기 위한 목 사용

  • 테스트가 파일 시스템에 접근하지 않게되므로, 테스트도 만족되고 유지비용도 절감된다.
  • 리팩터링 후에도 회귀 방지와 리팩터링 내성이 나빠지지 않는다.

초기 버전 목 사용

회귀 방지 좋음 좋음
리팩터링 내성 좋음 좋음
빠른 피드백 나쁨 좋음
유지 보수성 나쁨 중간

6.4.3 함수형 아키텍처로 리팩터링하기

  • 인터페이스 뒤로 부작용을 숨기고 해당 인터페이스를 주입하는 대신 부작용을 클래스 외부로 완전히 이동할 수 있다.
  • 가변 셀과 함수형 코어는 함수형 아키텍처를 형성한다.
    • 가변 셀은 작업 디렉터리에서 파일과 해당 내용을 수집해 함수형 코어에게 준다음, 반환 값을 파일 시스템의 변경 사항으로 변환한다.
  • 더이상 복잡한 목 설정이 필요없고, 단순한 입출력만 필요하므로 테스트 가독성을 크게 향상시킨다.

초기 버전 목 사용 출력 기반

회귀 방지 좋음 좋음 좋음
리팩터링 내성 좋음 좋음 좋음
빠른 피드백 나쁨 좋음 좋음
유지 보수성 나쁨 중간 좋음

6.4.4. 예상되는 추가 개발

  • 작업 디렉터리가 비어있는 경우 새로운 파일 작성
  • 기존 파일에 새 레코드 추가
  • 현재 파일의 항목 수가 한도를 초과할 때 다른 파일 작성

6.5 함수형 아키텍처의 단점 이해하기

6.5.1 함수형 아키텍처 적용 가능성

  • 함수형 코어의 클래스는 협력자로 작동하면 안 되고, 작업의 결과인 값으로 작동해야 함

6.5.2 성능 단점

  • 함수형 아키텍처와 전통적인 아키텍처 사이의 선택은 성능과 코드 유지 보수성(제품코드와 테스트 코드 모두) 간의 절충
  • 함수형 아키텍처는 유지 보수성 향상을 위해 성능을 희생한다.

6.5.3 코드베이스 크기 증가

  • 모든 코드베이스를 함수형 아키텍처로 전환할 수는 없다.
  • 함수형 아키텍처를 전략적으로 적용해야하며, 시스템의 복잡도와 중요성을 고려해야 한다.
  • 코드베이스가 단순하거나 중요하지 않으면, 함수형 아키텍처에 필요한 초기 투자는 별 효과가 없다.