[소프트웨어 테스트] 04. 계약 설계
[소프트웨어 테스트] 04. 계약 설계
소프트웨어 테스트 시리즈의 글입니다.
복잡한 소프트웨어를 설계하다 보면 제약사항이 생기기 마련이다.
이러한 제약사항은 각 클래스에 대한 명확한 계약으로 정의된다.
이렇게 계약을 통해 설계하는 방법에 대해 알아보자
4.1 사전 조건과 사후 조건
- 사전 조건 : 메서드가 받아들인 입력값이 요구사항을 준수하도록 보장
- 사후 조건 : 메서드가 다른 메서드에 약속한 것을 반환하도록 보장 문서에 사전, 사후 조건을명확히 기술하는 일은 중요하고 매우 권장된다
4.1.1 단언 키워드
보통 assert 문으로 단언문을 작성.
보통 이녀석은 항상 일반적인오류인 AssertionError 를 발생시키기 때문에 더 세부적인 예외를 던지고 싶다면 다른 방식으로 예외를 던져야한다.
4.1.2 강한 조건과 약한 조건
사전, 사후조건 정의 시 조건의 강도를 어느정도로 해야할지는 매우 중요. 약한 사전조건은 caller가 이 메서드를 쉽게 호출할 수 있음. 필자는 강한조건을 선호. (코드에서의 실수, 버그를 줄여준다고 생각) 사후조건을 약하게하는건?(예외를 던지는 대신에 값을 반환한다거나.) → ㄴㄴ. 버그를 잘 잡기 위해서는 예외가 맞다 (개인적으로 생각하는 최악 : return None 제발 ㅜㅜ)
4.2 불변식
불변식 = 메서드의 사전, 사후 모두의 경우에서 유지되어야하는 조건. 즉 객체나 데이터의 lifecycle 전체에 해당하는 조건. ex . 장바구니에 있는 제품의 합계는 절대 음수가 될 수 없다. 불변식은 메서드 실행 도중에는 유지되지 않을수도 있고 불변량을 잠시 깨뜨릴수도 있지만, 어쨌든 결국에는 불변식이 유지되도록 보장해야함.
4.3 계약 변경과 리스코프 치환 원칙
클래스나 메서드의 계약을 바꾼다면? → 이상적인 경우에는 거의 정의 후에 변경되지 않지만 현업에서는 결국 종종 일어나는 일.. 변경으로 인한 영향 파악은 해당 클래스의 의존성을 살펴보는것. 일반적으로 사전조건을 약화시켰다면 클라와의 계약은 유지된다. 하지만 사후조건이 약해진다면 클라와의 계약은 망가진다.
4.3.1 상속과 계약
자식클래스가 overrideing한 메서드의 계약이 변경된다면? ⇒ LSP (리스코프의 치환법칙) : 자식클래스는 부모클래스로 치환 가능해야함.
- 자식클래스의 사전조건은 부모클래스의 사전조건보다 같거나 약해야함
- 자식클래스의 사후조건은 부모클래스의 사후조건보다 같거나 강해야함.
4.4 계약에 의한 설계와 테스트는 어떤 관련이 있는가?
사전 조건, 사후 조건, 불변식을 정의하고 단언문을 통해 자동화해둔다면
- 단언문을 통해 제품 코드의 버그를 일찍 발견할 수 있다
- 사전 조건, 사후 조건, 불변식은 개발자에게 테스트 대상을 제공한다
- 명시적인 계약은 소비자의 삶을 편안하게 해준다
4.5 현업에서의 계약에 의한 설계
4.5.1 강한 사전 조건 vs 약한 사전 조건
계약을 강하게할지? 약하게할지? 는 결국 트레이드 오프인데..
- 약한 사전 조건 : 클라가 사용하기 편함
- 강한 사전 조건 : 클라가 사용하기 불편함. (사전조건을 위반하지않는 인풋에대한 부담을 클라가 떠안기때문에..) 명확한 답은 없음. 결국 맥락에 따라 다를듯. 이를테면 보통 라이브러리(=범용적으로 사용되는 녀석들)는 약한 사전조건을 선호.
4.5.2 유효성 검사 vs 계약
- 유효성 검사 : 사용자로부터 들어올 수 있는 불량 데이터나 유효하지 않은 데이터가 시스템에 침투하지 못하도록 함
- 계약 : 클래스간 의사소통이 문제없이 일어날 수 있도록함. (데이터는 이미 유효하다고 가정.) 계약 위반이 일어난다면 프로그램은 중지되어야함. (=예상치 못한 일이 발생한것임.) 둘은 서로 다르기때문에 둘 다 이루어져야함. 반복은 어떻게 피하는가? 이미 확실히 수행했다면 다시 안해도 되지않을까.. 하지만 필요하다면 약간의 중복과 비용은 감수하는게 좋겠다.
4.5.3 단언 vs 예외
이번에도 정답은없고 맥락에 따라 다르겠지만 저자는 대충 아래와 같이 추천.
- 라이브러리나 유틸리티 클래스에 대한 계약 : 예외를 선호
- 비즈니스 클래스와 클래스간의 계약 : 단언문을 선호
- 비즈니스 클래스를 모델링하지만 데이터 유효성이 확실하지 않은 경우 : 예외를 선호
4.5.4 예외 vs 부드러운 반환값
클라가 좀더 편하게만드려면 예외던지는 대신 반환값(ex. 빈 문자열)을 부드럽게 만드는것..
- 일어나서 안되는 동작이 생겼을 때 클라가 그것을 어떻게 다루어야할지 모른다면 예외를 던짐.
- 클라가 메서드에 부드러운 값을 반환해서 계속 작업할 수 있는 경우라면 부드러운 반환값을 던짐.
4.5.5 계약에 의한 설계를 사용하지 않는 경우
사용하지말아야할 때를 아는것은 무척 중요하지만.. 계약에 의한 설계 개념을 사용하지 않을 타당한 이유가 딱히 없다. (= 사용해라!)
4.5.6 사전 조건, 사후 조건, 불변식 테스트
사전 조건, 사후 조건, 불변식 검사가 제품코드 테스트나 마찬기지긴함. 유효성검사 = 데이터가 유효한지 확인 사전조건 = 메서드가 어떤 조건에서 실행되는지 명시 보통 유효성 검사에대해서는 테스트 작성. 단언문에 대해서는 굳이 작성 X.. (다른 테스트에의해 자연스럽게 수행됨)