56
xUnit Test Pattern 15. 코드 냄새 박상혁 http://pixelmine.tistory.com 아꿈사 http://andstudy.com

xunittestpatternchapter15

  • Upload
    sh-park

  • View
    951

  • Download
    2

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: xunittestpatternchapter15

xUnit Test Pattern

15장. 코드 냄새

박상혁 http://pixelmine.tistory.com

아꿈사 http://andstudy.com

Page 2: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 3: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 4: xunittestpatternchapter15

애매한 테스트(Obscure Test)

테스트를 한 눈에 이해하기 어렵다긴 테스트, 복잡한 테스트, 장황한 테스트

자동테스트의 목표1. SUT가 어떻게 동작해야 하는가에 대한 문서역할

2. 실행해볼 수 있는 자체 검증 명세

테스트를 실행할 수 있게 구현하다 보면 복잡해지기 때문에 이 두가지 목표를 동시에 만족하기 어렵다.

Page 5: xunittestpatternchapter15

애매한 테스트(Obscure Test)

욕심쟁이 테스트하나의 메소드에서 너무 많은 기능을 검증하려는 테스트

미스터리한 손님픽스처와 검증로직간의 인과 관계가 보이지 않는 테스트

일반 픽스처기능 검증에 필요 이상으로 큰 픽스처를 생성하거나 참조한다

관련 없는 정보정보가 너무 많아 실제 동작에 영향을 미치는 것이 무엇인지 파악하기 힘들다

하드코딩된 테스트 데이터데이터 값이 하드 코딩돼 있어 입력과 기대 결과값 사이의 인과 관계가 애매하다

간접 테스팅테스트 메소드와 SUT가 다른 객체를 통해 간접적으로 상호작용한다

Page 6: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

Page 7: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

욕심쟁이 테스트(Eager Test)

Page 8: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

미스터리한 손님(Mystery Guest)

Page 9: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

일반 픽스처(General Fixture)

Page 10: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

관련 없는 정보(Irrelevant Information)

Page 11: xunittestpatternchapter15

애매한 테스트(Obscure Test)

증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

이것 저것 '없는 거 빼고 전부 다' 검증한다

어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

외부 정보를 찾지 않고는 동작을 이해하기 어렵다

필요이상으로 큰 픽스처를 구축한다

'픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

테스트 검증 코드가 복잡하다

하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

하드 코딩된 테스트 데이터(Hard-Coded Test Data)

Page 12: xunittestpatternchapter15

애매한 테스트(Obscure Test)

• 증상 : 테스트에서 검증하는 동작을 이해하기 힘들다

– 이것 저것 '없는 거 빼고 전부 다' 검증한다

– 어디까지가 픽스처 설치인지, 어디서부터 SUT실행부인지 알기 어렵다

– 픽스처 설치나 결과 검증부가 테스트에서 볼 수 없는 정보에 의존한다

– 외부 정보를 찾지 않고는 동작을 이해하기 어렵다

– 필요이상으로 큰 픽스처를 구축한다

– '픽스처-SUT실행-결과값'사이의 인과관계 파악이 힘들다

– 객체에 전달되는 값 중 무엇이 기대출력에 영향을 주는지 알기 어렵다

– 픽스처 설치 로직이 길고, 무엇을 검증하려는지 알기 어렵다

– 테스트 검증 코드가 복잡하다

– 하드코딩된 값이 어떻게 서로 관련되어 있는지 알기 어렵다

– 어떤 값들이 SUT의 동작에 영향을 주는지 알기 어렵다

– 검증해야 하는 객체가 아닌 다른 객체와 주로 상호작용한다

간접 테스팅(Indirect Testing)

Page 13: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

Page 14: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

욕심쟁이 테스트(Eager Test)

Page 15: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

미스터리한 손님(Mystery Guest)

Page 16: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

일반 픽스처(General Fixture)

Page 17: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

관련 없는 정보(Irrelevant Information)

Page 18: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸 때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

하드 코딩된 테스트 데이터(Hard-Coded Test Data)

Page 19: xunittestpatternchapter15

애매한 테스트(Obscure Test)

미치는 영향

이해하기 힘들고 유지보수가 어렵다

문서로서의 테스트를 만들기 어렵다

테스트 유지비용 상승한다

버그 투성이 테스트가 된다

테스트 디버깅 데이터를 잃게 된다

픽스처와 기대결과 사이의 인과관계를 알기 어렵다

변덕스러운 테스트가 생긴다

각 테스트에서 픽스처를 어떻게 사용하는지 이해하기 힘들다

깨지기 쉬운 픽스쳐가 된다

느린 테스트가 될 수 있다

공유픽스처를 쓸때 다른 테스트에서 같은 값을 쓰는 경우 충돌이 생긴다

깨지기 쉬운 테스트가 된다

모든 곳을 테스트 하기 불가능하다

간접 테스팅(Indirect Testing)

Page 20: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

– 테스트 용이성을 생각하지 않고 설계했다

Page 21: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

욕심쟁이 테스트(Eager Test)

Page 22: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

미스터리한 손님(Mystery Guest)

SUT 메소드에 전달되는 외부 파일의 내용이 SUT의동작을 결정

리터럴키로 식별되는 DB 레코드를 읽어 객체에 쓴 뒤이를 테스트에서 사용하거나 SUT에 전달

파일에서 읽어들인 내용을 기대결과값을 검증하는 단언 메소드 호출에 사용

설치 데코레이터로 공유 픽스처를 만들고 결과 검증로직에서는 공유 픽스처의 객체들을 변수로 참조

암묵적 설치로 일반 픽스처를 설치하고 테스트 메소드에서 인스턴스 변수나 클래스 변수로 접근

Page 23: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

일반 픽스처(General Fixture)

Page 24: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

관련 없는 정보(Irrelevant Information)

Page 25: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

하드 코딩된 테스트 데이터(Hard-Coded Test Data)

Page 26: xunittestpatternchapter15

애매한 테스트(Obscure Test)

원인

테스트 메소드에 정보가 너무 많다

테스트 메소드에 정보가 너무 적다

코드를 깔끔하고 간단하게 유지하려는 의지가 없다

코드를 '그냥 인라인으로' 작성한다

테스트가 외부자원에 의존한다

여러 테스트를 지원하는 픽스처를 쓴다

테스테 상관없는 리터럴 값이 너무 많다

절차형 상태 검증을 쓴다

잘라 붙여넣기로 테스트 로직을 재사용한다

테스트에서 접근하려는 클래스의 SUT부분이 private이다

테스트 용이성을 생각하지 않고 설계했다

간접 테스팅(Indirect Testing)

Page 27: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

Page 28: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

욕심쟁이 테스트(Eager Test)

Page 29: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 잘 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

미스터리한 손님(Mystery Guest)

Page 30: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

일반 픽스처(General Fixture)

Page 31: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

관련 없는 정보(Irrelevant Information)

Page 32: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

하드 코딩된 테스트 데이터(Hard-Coded Test Data)

Page 33: xunittestpatternchapter15

애매한 테스트(Obscure Test)

해결책

더 좋은 결함 국소화를 제공하는 독립적인 단일 조건 테스트 스위트로 만든다

인라인 설치로 신선한 픽스처를 쓴다

픽스처 안의 객체들에 찾기메소드로 접근하는 것을 고려해보자

파일 이름을 적당히 붙여 안에 어떤 데이터가 들어있는지 짐작할 수 있게 해준다

최소 픽스처, 신선한 픽스처 사용

테스트별로 가상의 데이터베이스 샌드박스를 만든다

관련 있는 정보만 인자로 받는 인자를 받는 생성 메소드 호출

설치부와 검증부에 필요한 픽스처 값을 적당히 초기화한 상수로 바꾼다

결과 검증 로직에서 기대 객체로 한번에 단언한다

복잡한 절차적 검증로직을 숨기는 맞춤 단언문 사용

리터럴 상수를 다른 걸로 바꿔준다

별개의 생성값을 써서 테스트가 실행될 때마다 다른 값을 쓰게 보장해줘야 한다

SUT의 테스트 용이성을 위한 설계를 개선

SUT를 간접적으로 접근해야만 한다면 SUT API 캡슐화 사용

간접 테스팅(Indirect Testing)

Page 34: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 35: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

테스트에 실행 안 될 수도 있는 코드가 있다들쑥날쑥한 테스트 코드

완전 자동 테스트는 다른 코드의 동작을 검증하는 코드다

완전 자동 테스트 코드가 복잡하다면......?

테스트를 위한 테스트......?

테스트가 필요없을 정도로 단순하게 만드는 것이 정답

테스트 내 조건문 로직은 필요 이상으로 테스트를 복잡하게 만드는 요인 중 하나다

Page 36: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

유연한 테스트언제 어디서 실행되느냐에 따라 다른 기능을 검증하는 테스트

검증 조건문 로직기대 결과 검증에 조건문 사용

테스트 내 제품 로직

복잡한 해체

여러 테스트 조건

Page 37: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

증상 : 테스트 코드 내에 반복문이나 조건문이 있다

테스트가 상황에 따라 다른 일을 할 수 있게 조건문 로직이 들어 있다

테스트의 결과 검증부에 조건문 로직이 들어있다

픽스처 해체 코드가 복잡하다

여러 입력값과 그 기대 결과값에 같은 테스트 로직 적용

Page 38: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

미치는 영향

테스트 코드에서 무엇을 하는지 알기 어렵다

테스트가 결정론적이지 않아 디버깅하기 어렵다

어려운 작업에 대해 테스트를 정확하게 작성하기 어렵다

테스트가 이해하기 어려워 유지보수가 힘들다

모든 제어경로가 테스트 되었는지 알 수 없다

Page 39: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

원인

SUT가 올바른 데이터를 반환하지 않았을 때의 if문 처리

여러 객제를 한꺼번에 검증하기 위해 반복문 사용

복잡한 객체나 다형성 데이터 구조를 검증

테스트 픽스처나 기대 객체 초기화시 하나의 테스트에서 여러 다른 경우 검증

존재하지 않는 픽스처 객체를 해체하지 않기 위해 if문 사용

환경에 대한 제어능력 부족

가비지 컬렉션 시스템이 해결해 줄 수 없는 지속적인 자원을 많이 사용

Page 40: xunittestpatternchapter15

테스트 내 조건문 로직(Conditional Test Logic)

해결책

SUT에서 '바꿀 수 있는 의존'을 지원하게 리팩토링한다

보호 단언문 사용

복잡한 객체를 검증할 때는 기대객체에 동등 단언문 사용

테스트용 동등을 정의한 맞춤 단언문 사용

테스트 유틸리티 메소드나 공통 인자를 받는 테스트 사용

입력된 값에 대한 계산된 값을 쓴다

암묵적 해체, 자동 해체 사용

신선한 픽스처, 테스트 대역을 사용해 지속되는 객체를 쓰지 않는다

Page 41: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 42: xunittestpatternchapter15

테스트하기 힘든 코드(Hard-to-Test Code)

코드가 테스트 하기 어렵다

강하게 결합된 코드

비동기 코드

테스트할 수 없는 테스트 코드

Page 43: xunittestpatternchapter15

테스트하기 힘든 코드(Hard-to-Test Code)

증상

원래부터 테스트 하기 힘든 코드

여러 다른 클래스와 함께 테스트 해야만 하는 코드

직접 메소드 호출로 테스트할 수 없는 클래스

테스트 메소드의 내용이 복잡하다

테스트가 올바른지 확신할 수 없다

Page 44: xunittestpatternchapter15

테스트하기 힘든 코드(Hard-to-Test Code)

미치는 영향

코드의 품질을 쉽게 검증할 수 없다

테스트 문서화에 큰 공을 들이지 않으면 품질 평가를 반복하기 어렵다

단위 테스트가 어렵다

테스트가 복잡하고 실행이 느려진다

버그투성이 테스트가 되기 쉽다

테스트 유지 비용이 비싸다

테스트를 제대로 작성하기 어렵다

Page 45: xunittestpatternchapter15

테스트하기 힘든 코드(Hard-to-Test Code)

원인

설계가 조잡하다

객체지향 설계경험이 부족하다

액티브 객체와 강하게 결합되어 있다

데스트코드는 원래 테스트하기 어렵다

Page 46: xunittestpatternchapter15

테스트하기 힘든 코드(Hard-to-Test Code)

해결책

결합을 분리한다 : 테스트 대역, 테스트 스텁, 모의 객체

'레거시 코드 활용 전략'을 읽어본다

로직과 비동기 접근 매커니즘 분리 : 대강 만든 객체

테스트 메소드들 아주 단순하게 만든다

Page 47: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 48: xunittestpatternchapter15

테스트 코드 중복(Test Code Duplication)

여러 번 반복되는 테스트 코드같은 주제에 대해 약간씩 다른 시나리오로 테스트 해야 하는 경우

'잘라 붙여넣기' 코드 재사용

바퀴 재발명 하기

Page 49: xunittestpatternchapter15

테스트 코드 중복(Test Code Duplication)

증상

같은 코드가 여러 테스트에서 반복된다

한 테스트 안에서 비슷한 구문이 반복된다

미치는 영향

SUT메소드 의미가 변경되면 모든 복사본에 유지보수 해야한다

테스트 유지 비용이 늘어난다

Page 50: xunittestpatternchapter15

테스트 코드 중복(Test Code Duplication)

원인

리팩토링 기술이나 경험이 부족

일정에 대한 압박

어떤 테스트 유틸리티 메소드가 있는지 모른다

해결책

메소트 뽑아내기

생성 메소드, 찾기 메소드

맞춤 단언문, 검증 메소드

'인자 도입' 리팩토링

테스트 유틸리티 메소드 확인

Page 51: xunittestpatternchapter15

15장에서 다루는 냄새

애매한 테스트

테스트 내 조건문 로직

테스트하기 힘든 코드

테스트 코드 중복

제품 코드 내 테스트 로직

Page 52: xunittestpatternchapter15

제품 코드 내 테스트 로직(Test Logic In Production)

제품 코드에 테스트에서만 실행돼야 하는 코드가 들어있다

테스트 훅

테스트 전용

제품 코드 내 테스트 의존

동등 오염

Page 53: xunittestpatternchapter15

제품 코드 내 테스트 로직(Test Logic In Production)

증상

순전히 테스트에서만 필요한 로직이 SUT안에 들어 있다

SUT가 테스트 중일때 다르게 실행되는 로직이 있다

SUT일부 메소드가 테스트에서만 쓰이고 있다

실제 private 이어야 하는 속성이 public 으로 돼 있다

제품 코드만 빌드할 수가 없다

테스트 실행이 없는 경우 제품 코드를 실행할 수 없다

테스트에서의 필요로 equals 메소드를 변경

SUT에서 equals 의 정의를 변경

Page 54: xunittestpatternchapter15

제품 코드 내 테스트 로직(Test Logic In Production)

미치는 영향

제품 상태에서 테스트 코드가 실행되면 심각한 문제가 생길 수 있다

SUT를 더 복잡하게 만든다

제품의 실행 크기가 늘어난다

제품에서 뜻하지 않게 테스트 코드가 실행될 수 있다

새로운 요구사항을 지원하는 equals 로직을 추가하기 어렵다

원인

알려진 값을 리턴해 SUT동작을 결정적으로 만든다

테스트에 필요한 정보를 클래스로부터 노출

테스트에 필요한 정보 초기화에 더 많은 제어를 하기 위한 메소드 추가

모듈간 의존성에 신경을 쓰지 않는다

테스트용 동등의 개념을 잘 모른다

Page 55: xunittestpatternchapter15

제품 코드 내 테스트 로직(Test Logic In Production)

해결책

바꿀 수 있는 의존 사용 : 스트레티지 패턴

테스트용 하위클래스를 만들어 SUT의 특정 메소드를 오버라이딩한다

테스트 전용임을 분명하게 네이밍을 한다

의존관계를 신중히 관리한다

equals 수정 대신 맞춤 단언문으로 내장 동등 단언문을 쓰게 한다

동적 모의 객체 생성 도구를 쓴다면 비교자를 쓴다

기대 객체의 테스트용 하위 클래스에 equals 메소드를 구현한다

Page 56: xunittestpatternchapter15