Effective Unit Testing (케일)
- remarkjs로 작성후 브라우저로 pdf 인쇄
기본적으로 Effective Unit Testing을 바탕으로 내용을 만들었고, 좀더 공유하고 싶은 내용에 살을 붙였음.
예제 코드는 책에 없는건 직접 만들어 봤으나 의미가 잘 전달되지 않을수는 있다고 생각함.
깨끗한 테스트 원칙은 '클린코드' 책에 나오는 내용임.
TDD 테스트 주도 개발이며, 하나의 개발 방법론 입니다.
- TDD는 반복 테스트을 이용한 소프트웨어 개발법이다. 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 소프트웨어를 구현한다.
- TDD의 목표는 작동하는 깔끔한 코드 “Clean code that works”
- TDD는 아래 단계의 반복으로 진행된다.
빨강 : 실패하는 작은 테스트 케이스를 작성한다. 처음에는 컴파일조차 안될 수 있다.
초록 : 테스트를 통과하는 코드를 작성한다.
리펙터링 : 테스트를 통과하기 위해 만든 코드의 모든 중복을 제거하고, 불명확한 것을 명확히 한다.
이러한 단계로 인해 TDD는 “업무 코드 작성 전에 테스트 코드를 먼저 만드는 것”으로 정의되기도 한다
Effective Unit Testing (케일)
- remarkjs로 작성후 브라우저로 pdf 인쇄
기본적으로 Effective Unit Testing을 바탕으로 내용을 만들었고, 좀더 공유하고 싶은 내용에 살을 붙였음.
예제 코드는 책에 없는건 직접 만들어 봤으나 의미가 잘 전달되지 않을수는 있다고 생각함.
깨끗한 테스트 원칙은 '클린코드' 책에 나오는 내용임.
TDD 테스트 주도 개발이며, 하나의 개발 방법론 입니다.
- TDD는 반복 테스트을 이용한 소프트웨어 개발법이다. 작은 단위의 테스트 케이스를 작성하고 이를 통과하는 코드를 추가하는 단계를 반복하여 소프트웨어를 구현한다.
- TDD의 목표는 작동하는 깔끔한 코드 “Clean code that works”
- TDD는 아래 단계의 반복으로 진행된다.
빨강 : 실패하는 작은 테스트 케이스를 작성한다. 처음에는 컴파일조차 안될 수 있다.
초록 : 테스트를 통과하는 코드를 작성한다.
리펙터링 : 테스트를 통과하기 위해 만든 코드의 모든 중복을 제거하고, 불명확한 것을 명확히 한다.
이러한 단계로 인해 TDD는 “업무 코드 작성 전에 테스트 코드를 먼저 만드는 것”으로 정의되기도 한다
2. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
3. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
4. 애매한 테스트(Obscure Test)
테스트를 한 눈에 이해하기 어렵다
긴 테스트, 복잡한 테스트, 장황한 테스트
자동테스트의 목표
1. SUT가 어떻게 동작해야 하는가에 대한 문서역할
2. 실행해볼 수 있는 자체 검증 명세
테스트를 실행할 수 있게 구현하다 보면 복잡해지기 때문에 이 두
가지 목표를 동시에 만족하기 어렵다.
5. 애매한 테스트(Obscure Test)
욕심쟁이 테스트
하나의 메소드에서 너무 많은 기능을 검증하려는 테스트
미스터리한 손님
픽스처와 검증로직간의 인과 관계가 보이지 않는 테스트
일반 픽스처
기능 검증에 필요 이상으로 큰 픽스처를 생성하거나 참조한다
관련 없는 정보
정보가 너무 많아 실제 동작에 영향을 미치는 것이 무엇인지 파악하기 힘들다
하드코딩된 테스트 데이터
데이터 값이 하드 코딩돼 있어 입력과 기대 결과값 사이의 인과 관계가 애매하다
간접 테스팅
테스트 메소드와 SUT가 다른 객체를 통해 간접적으로 상호작용한다
6. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
7. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
욕심쟁이 테스트(Eager Test)
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
8. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
미스터리한 손님(Mystery Guest)
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
9. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
일반 픽스처(General Fixture)
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
10. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
관련 없는 정보(Irrelevant Information)
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
11. 애매한 테스트(Obscure Test)
증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
하드 코딩된 테스트 데이터(Hard-Coded Test Data)
이것 저것 '없는 거 빼고 전부 다' 검증한다
어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
외부 정보를 찾지 않고는 동작을 이해하기 어렵다
필요이상으로 큰 픽스처를 구축한다
'픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
테스트 검증 코드가 복잡하다
하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
12. 애매한 테스트(Obscure Test)
• 증상 : 테스트에서 검증하는 동작을 이해하기 힘들다
간접 테스팅(Indirect Testing)
– 이것 저것 '없는 거 빼고 전부 다' 검증한다
– 어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다
– 픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다
– 외부 정보를 찾지 않고는 동작을 이해하기 어렵다
– 필요이상으로 큰 픽스처를 구축한다
– '픽스처-SUT실행-결과값' 사이의 인과관계 파악이 힘들다
– 객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다
– 픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다
– 테스트 검증 코드가 복잡하다
– 하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다
– 어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다
– 검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다
13. 애매한 테스트(Obscure Test)
미치는 영향
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
14. 애매한 테스트(Obscure Test)
미치는 영향
욕심쟁이 테스트(Eager Test)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
15. 애매한 테스트(Obscure Test)
미치는 영향
미스터리한 손님(Mystery Guest)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
16. 애매한 테스트(Obscure Test)
미치는 영향
일반 픽스처(General Fixture)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
17. 애매한 테스트(Obscure Test)
미치는 영향
관련 없는 정보(Irrelevant Information)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
18. 애매한 테스트(Obscure Test)
미치는 영향
하드 코딩된 테스트 데이터(Hard-Coded Test Data)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
19. 애매한 테스트(Obscure Test)
미치는 영향
간접 테스팅(Indirect Testing)
이해하기 힘들고 유지보수가 어렵다
문서로서의 테스트를 만들기 어렵다
테스트 유지비용 상승한다
버그 투성이 테스트가 된다
테스트 디버깅 데이터를 잃게 된다
픽스처와 기대결과 사이의 인과관계를 알기 어렵다
변덕스러운 테스트가 생긴다
각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다
깨지기 쉬운 픽스쳐가 된다
느린 테스트가 될 수 있다
공유픽스처를 쓸때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다
깨지기 쉬운 테스트가 된다
모든 곳을 테스트 하기 불가능하다
20. 애매한 테스트(Obscure Test)
원인
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
– 테스트 용이성을 생각하지 않고 설계했다
21. 애매한 테스트(Obscure Test)
원인
욕심쟁이 테스트(Eager Test)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
테스트 용이성을 생각하지 않고 설계했다
22. 애매한 테스트(Obscure Test)
원인
미스터리한 손님(Mystery Guest)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다 SUT 메소드에 전달되는 외부 파일의 내용이 SUT의
여러 테스트를 지원하는 픽스처를 쓴다 결정
동작을
리터럴키로 식별되는 DB 레코드를 읽어 객체에 쓴 뒤
테스테 상관없는 리터럴 값이 너무 많다 테스트에서 사용하거나 SUT에 전달
이를
절차형 상태 검증을 쓴다 파일에서 읽어들인 내용을 기대결과값을 검증하는 단
언 메소드 호출에 사용
잘라 붙여넣기로 테스트 로직을 재사용한다
설치 데코레이터로 공유 픽스처를 만들고 결과 검증
테스트에서 접근하려는 클래스의 SUT부분이 private이다
로직에서는 공유 픽스처의 객체들을 변수로 참조
테스트 용이성을 생각하지 않고 설계했다 설치로 일반 픽스처를 설치하고 테스트 메소
암묵적
드에서 인스턴스 변수나 클래스 변수로 접근
23. 애매한 테스트(Obscure Test)
원인
일반 픽스처(General Fixture)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
테스트 용이성을 생각하지 않고 설계했다
24. 애매한 테스트(Obscure Test)
원인
관련 없는 정보(Irrelevant Information)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
테스트 용이성을 생각하지 않고 설계했다
25. 애매한 테스트(Obscure Test)
원인
하드 코딩된 테스트 데이터(Hard-Coded Test Data)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
테스트 용이성을 생각하지 않고 설계했다
26. 애매한 테스트(Obscure Test)
원인
간접 테스팅(Indirect Testing)
테스트 메소드에 정보가 너무 많다
테스트 메소드에 정보가 너무 적다
코드를 깔끔하고 간단하게 유지하려는 의지가 없다
코드를 '그냥 인라인으로' 작성한다
테스트가 외부자원에 의존한다
여러 테스트를 지원하는 픽스처를 쓴다
테스테 상관없는 리터럴 값이 너무 많다
절차형 상태 검증을 쓴다
잘라 붙여넣기로 테스트 로직을 재사용한다
테스트에서 접근하려는 클래스의 SUT부분이 private이다
테스트 용이성을 생각하지 않고 설계했다
27. 애매한 테스트(Obscure Test)
해결책
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
28. 애매한 테스트(Obscure Test)
해결책
욕심쟁이 테스트(Eager Test)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
29. 애매한 테스트(Obscure Test)
해결책
미스터리한 손님(Mystery Guest)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 잘 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
30. 애매한 테스트(Obscure Test)
해결책
일반 픽스처(General Fixture)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
31. 애매한 테스트(Obscure Test)
해결책
관련 없는 정보(Irrelevant Information)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
32. 애매한 테스트(Obscure Test)
해결책
하드 코딩된 테스트 데이터(Hard-Coded Test Data)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
33. 애매한 테스트(Obscure Test)
해결책
간접 테스팅(Indirect Testing)
더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다
인라인 설치로 신선한 픽스처를 쓴다
픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자
파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다
최소 픽스처, 신선한 픽스처 사용
테스트별로 가상의 데이터베이스 샌드박스를 만든다
관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출
설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다
결과 검증 로직에서 기대 객체로 한번에 단언한다
복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용
리터럴 상수를 다른 걸로 바꿔준다
별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다
SUT의 테스트 용이성을 위한 설계를 개선
SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용
34. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
35. 테스트 내 조건문 로직(Conditional Test Logic)
테스트에 실행 안 될 수도 있는 코드가 있다
들쑥날쑥한 테스트 코드
완전 자동 테스트는 다른 코드의 동작을 검증하는 코드다
완전 자동 테스트 코드가 복잡하다면......?
테스트를 위한 테스트......?
테스트가 필요없을 정도로 단순하게 만드는 것이 정답
테스트 내 조건문 로직은 필요 이상으로 테스트를 복잡하게 만드
는 요인 중 하나다
36. 테스트 내 조건문 로직(Conditional Test Logic)
유연한 테스트
언제 어디서 실행되느냐에 따라 다른 기능을 검증하는 테스트
검증 조건문 로직
기대 결과 검증에 조건문 사용
테스트 내 제품 로직
복잡한 해체
여러 테스트 조건
37. 테스트 내 조건문 로직(Conditional Test Logic)
증상 : 테스트 코드 내에 반복문이나 조건문이 있다
테스트가 상황에 따라 다른 일을 할 수 있게 조건문 로직이 들어 있다
테스트의 결과 검증부에 조건문 로직이 들어있다
픽스처 해체 코드가 복잡하다
여러 입력값과 그 기대 결과값에 같은 테스트 로직 적용
38. 테스트 내 조건문 로직(Conditional Test Logic)
미치는 영향
테스트 코드에서 무엇을 하는지 알기 어렵다
테스트가 결정론적이지 않아 디버깅하기 어렵다
어려운 작업에 대해 테스트를 정확하게 작성하기 어렵다
테스트가 이해하기 어려워 유지보수가 힘들다
모든 제어경로가 테스트 되었는지 알 수 없다
39. 테스트 내 조건문 로직(Conditional Test Logic)
원인
SUT가 올바른 데이터를 반환하지 않았을 때의 if문 처리
여러 객제를 한꺼번에 검증하기 위해 반복문 사용
복잡한 객체나 다형성 데이터 구조를 검증
테스트 픽스처나 기대 객체 초기화시 하나의 테스트에서 여러 다른 경우 검증
존재하지 않는 픽스처 객체를 해체하지 않기 위해 if문 사용
환경에 대한 제어능력 부족
가비지 컬렉션 시스템이 해결해 줄 수 없는 지속적인 자원을 많이 사용
40. 테스트 내 조건문 로직(Conditional Test Logic)
해결책
SUT에서 '바꿀 수 있는 의존'을 지원하게 리팩토링한다
보호 단언문 사용
복잡한 객체를 검증할 때는 기대객체에 동등 단언문 사용
테스트용 동등을 정의한 맞춤 단언문 사용
테스트 유틸리티 메소드나 공통 인자를 받는 테스트 사용
입력된 값에 대한 계산된 값을 쓴다
암묵적 해체, 자동 해체 사용
신선한 픽스처, 테스트 대역을 사용해 지속되는 객체를 쓰지 않는다
41. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
43. 테스트하기 힘든 코드(Hard-to-Test Code)
증상
원래부터 테스트 하기 힘든 코드
여러 다른 클래스와 함께 테스트 해야만 하는 코드
직접 메소드 호출로 테스트할 수 없는 클래스
테스트 메소드의 내용이 복잡하다
테스트가 올바른지 확신할 수 없다
44. 테스트하기 힘든 코드(Hard-to-Test Code)
미치는 영향
코드의 품질을 쉽게 검증할 수 없다
테스트 문서화에 큰 공을 들이지 않으면 품질 평가를 반복하기 어렵다
단위 테스트가 어렵다
테스트가 복잡하고 실행이 느려진다
버그투성이 테스트가 되기 쉽다
테스트 유지 비용이 비싸다
테스트를 제대로 작성하기 어렵다
45. 테스트하기 힘든 코드(Hard-to-Test Code)
원인
설계가 조잡하다
객체지향 설계경험이 부족하다
액티브 객체와 강하게 결합되어 있다
데스트코드는 원래 테스트하기 어렵다
46. 테스트하기 힘든 코드(Hard-to-Test Code)
해결책
결합을 분리한다 : 테스트 대역, 테스트 스텁, 모의 객체
'레거시 코드 활용 전략'을 읽어본다
로직과 비동기 접근 매커니즘 분리 : 대강 만든 객체
테스트 메소드들 아주 단순하게 만든다
47. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
48. 테스트 코드 중복(Test Code Duplication)
여러 번 반복되는 테스트 코드
같은 주제에 대해 약간씩 다른 시나리오로 테스트 해야 하는 경우
'잘라 붙여넣기' 코드 재사용
바퀴 재발명 하기
49. 테스트 코드 중복(Test Code Duplication)
증상
같은 코드가 여러 테스트에서 반복된다
한 테스트 안에서 비슷한 구문이 반복된다
미치는 영향
SUT메소드 의미가 변경되면 모든 복사본에 유지보수 해야한다
테스트 유지 비용이 늘어난다
50. 테스트 코드 중복(Test Code Duplication)
원인
리팩토링 기술이나 경험이 부족
일정에 대한 압박
어떤 테스트 유틸리티 메소드가 있는지 모른다
해결책
메소트 뽑아내기
생성 메소드, 찾기 메소드
맞춤 단언문, 검증 메소드
'인자 도입' 리팩토링
테스트 유틸리티 메소드 확인
51. 15장에서 다루는 냄새
애매한 테스트
테스트 내 조건문 로직
테스트하기 힘든 코드
테스트 코드 중복
제품 코드 내 테스트 로직
52. 제품 코드 내 테스트 로직(Test Logic In Production)
제품 코드에 테스트에서만 실행돼야 하는 코드가 들어있다
테스트 훅
테스트 전용
제품 코드 내 테스트 의존
동등 오염
53. 제품 코드 내 테스트 로직(Test Logic In Production)
증상
순전히 테스트에서만 필요한 로직이 SUT안에 들어 있다
SUT가 테스트 중일때 다르게 실행되는 로직이 있다
SUT일부 메소드가 테스트에서만 쓰이고 있다
실제 private 이어야 하는 속성이 public 으로 돼 있다
제품 코드만 빌드할 수가 없다
테스트 실행이 없는 경우 제품 코드를 실행할 수 없다
테스트에서의 필요로 equals 메소드를 변경
SUT에서 equals 의 정의를 변경
54. 제품 코드 내 테스트 로직(Test Logic In Production)
미치는 영향
제품 상태에서 테스트 코드가 실행되면 심각한 문제가 생길 수 있다
SUT를 더 복잡하게 만든다
제품의 실행 크기가 늘어난다
제품에서 뜻하지 않게 테스트 코드가 실행될 수 있다
새로운 요구사항을 지원하는 equals 로직을 추가하기 어렵다
원인
알려진 값을 리턴해 SUT동작을 결정적으로 만든다
테스트에 필요한 정보를 클래스로부터 노출
테스트에 필요한 정보 초기화에 더 많은 제어를 하기 위한 메소드 추가
모듈간 의존성에 신경을 쓰지 않는다
테스트용 동등의 개념을 잘 모른다
55. 제품 코드 내 테스트 로직(Test Logic In Production)
해결책
바꿀 수 있는 의존 사용 : 스트레티지 패턴
테스트용 하위클래스를 만들어 SUT의 특정 메소드를 오버라이딩한다
테스트 전용임을 분명하게 네이밍을 한다
의존관계를 신중히 관리한다
equals 수정 대신 맞춤 단언문으로 내장 동등 단언문을 쓰게 한다
동적 모의 객체 생성 도구를 쓴다면 비교자를 쓴다
기대 객체의 테스트용 하위 클래스에 equals 메소드를 구현한다