TDD 관점에서 볼 때 모의 대신 라이브 엔드 포인트를 테스트하면 나쁜 사람입니까?


16

나는 종교적으로 TDD를 따릅니다. 내 프로젝트는 일반적으로 의미있는 테스트 사례와 함께 85 % 이상의 테스트 범위를 갖습니다.

저는 HBase 와 많은 작업을 수행 하고 있으며 주요 클라이언트 인터페이스 인 HTable은 조롱하기가 매우 어렵습니다. 라이브 엔드 포인트를 사용하는 테스트를 작성하는 것보다 단위 테스트를 작성하는 데 3-4 배 더 걸립니다.

철학적으로 모의를 사용하는 테스트는 실제 엔드 포인트를 사용하는 테스트보다 우선해야한다는 것을 알고 있습니다. 그러나 HTable을 조롱하는 것은 심각한 고통이며 실제 HBase 인스턴스에 대한 테스트보다 이점을 제공한다는 것이 확실하지 않습니다.

우리 팀의 모든 직원은 워크 스테이션에서 단일 노드 HBase 인스턴스를 실행하고 Jenkins 상자에서 단일 노드 HBase 인스턴스를 실행하므로 가용성 문제가 아닙니다. 라이브 엔드 포인트 테스트는 모의를 사용하는 테스트보다 실행 시간이 더 오래 걸리지 만 실제로는 신경 쓰지 않습니다.

지금은 모든 수업에 대한 라이브 엔드 포인트 테스트 및 모의 기반 테스트를 작성합니다. 나는 목을 버리고 싶지만 결과적으로 품질이 떨어지기를 원하지 않습니다.

당신은 어떻게 생각하세요?


8
라이브 엔드 포인트는 실제로 단위 테스트가 아닌가? 통합 테스트입니다. 그러나 궁극적으로 그것은 실용주의의 문제 일 것입니다. 모형을 작성하거나 기능을 작성하거나 버그를 수정하는 데 시간을 할애 할 수 있습니다.
Robert Harvey

4
나는 자신의 코드에 대해 단위 테스트를 실행하여 타사 서비스를 중단하는 사람들의 이야기를 들었습니다. 이는 라이브 엔드 포인트에 연결되었습니다. 속도 제한은 단위 테스트가 일반적으로 수행하거나 신경 쓰지 않는 것이 아닙니다.

14
당신은 나쁜 사람이 아닙니다. 당신은 나쁜 일을하는 좋은 사람입니다.
Kyralessa

15
나는 종교적으로 TDD를 따릅니다. 어쩌면 문제일까요? 나는이 방법론 중 어느 것도 그렇게 심각하게 받아 들여지지 않는다고 생각한다 . ;)
FrustratedWithFormsDesigner

9
종교적으로 TDD를 준수한다는 것은 15 % 발견되지 않은 코드를 폐기한다는 의미입니다.
mouviciel

답변:


23
  • 내 첫 번째 권장 사항은 소유하지 않은 유형을 조롱하지 않는 것 입니다. HTable은 조롱하는 것이 정말 고통 스럽다고 언급했습니다. HTable의 기능 중 20 %를 노출시키는 어댑터로 대신 감싸고 필요한 경우 래퍼를 조롱해야 할 수도 있습니다.

  • 우리가 당신이 소유 한 유형에 대해 이야기하고 있다고 가정 해 봅시다. 모의 기반 테스트가 모든 것이 순조롭게 진행되는 행복한 경로 시나리오에 중점을 둔 경우 통합 테스트가 이미 동일한 경로를 테스트하고 있기 때문에 도랑을 잃지 않을 것입니다.

    그러나 테스트중인 시스템이 실제 실제 대상과 관계없이 공동 작업자 계약에 정의 된대로 발생할 수있는 모든 작은 일에 어떻게 반응해야하는지에 대해 생각하기 시작하면 격리 된 테스트가 흥미로워집니다. 그것은 일부 사람들이 기본 정확성 이라고 부르는 것의 일부 입니다. 그 작은 경우들과 더 많은 조합이있을 수 있습니다. 통합 테스트가 거칠어지기 시작하는 반면 격리 된 테스트는 빠르고 관리하기 쉬운 상태입니다.

    보다 구체적으로, HTable 어댑터의 메소드 중 하나가 빈 목록을 리턴하면 어떻게됩니까? null을 반환하면 어떻게됩니까? 연결 예외가 발생하면 어떻게합니까? 이러한 상황이 발생할 수있는 경우 어댑터 계약에 정의 되어야하며 , 소비자는 이러한 상황을 처리준비가되어 있으므로 테스트가 필요합니다.

요약하자면, 모의 기반 테스트 가 통합 테스트와 정확히 동일한 것을 테스트 한 경우 제거해도 품질이 저하되지 않습니다 . 그러나 추가적인 분리 테스트 (및 계약 테스트 ) 를 상상 하면 통합 테스트로 생각하기 어렵거나 테스트가 느린 결함을 처리함으로써 인터페이스 / 계약을 광범위하게 생각하고 품질을 향상시킬 수 있습니다.


+1이 경우 데이터베이스를 채우는 것보다 모의 테스트로 가장자리 케이스를 구성하는 것이 훨씬 쉽다는 것을 알았습니다.
Rob

대부분의 답변에 동의합니다. 그러나 어댑터 부분에 동의하지 않습니다. HTable은 베어 메탈이기 때문에 조롱하는 고통입니다. 예를 들어, 일괄 가져 오기 작업을 수행하려면 Get 개체 묶음을 만들고 목록에 넣은 다음 HTable.batch ()를 호출해야합니다. 조롱의 관점에서 볼 때 HTable.batch ()에 전달한 get 객체의 목록을 검사 한 다음 get () 객체의 해당 목록에 대한 올바른 결과를 반환하는 사용자 지정 Matcher를 만들어야하므로 이는 심각한 문제입니다. 심한 고통.
sangfroid

나는 모든 하우스 키핑을 처리하는 HTable을위한 친절하고 친숙한 래퍼 클래스를 만들 수 있다고 생각하지만 그 시점에서 ... HTable을 중심으로 프레임 워크를 작성하는 것처럼 느껴지고 실제로 내 직업이어야합니까? 보통 "프레임 워크를 구축하자!" 내가 잘못된 방향으로 가고 있다는 표시입니다. HBase를 더 친근하게 만들기 위해 수업을 쓰는 데 며칠을 보낼 수 있었으며, 그것이 내 시간을 잘 활용하는지 알 수 없습니다. 또한 평범한 오래된 HTable 객체 대신 인터페이스 또는 래퍼를 둘러싼 것이므로 코드가 더 복잡해집니다.
sangfroid

그러나 나는 당신의 주요 요점에 동의합니다. 그리고 통합 테스트와 동일한 것을 테스트하는 모의 테스트를 작성할 필요가 없다는 점에 분명히 동의합니다. 인터페이스 / 계약 테스트에 모의가 가장 좋은 것 같습니다. 조언 주셔서 감사합니다-이것은 많은 도움이되었습니다!
sangfroid

HTable이 실제로 무엇을하고 어떻게 사용하는지 전혀 알지 못하므로 래퍼 예제를 글자로 보지 마십시오. 포장하는 것이 상대적으로 작다고 생각했기 때문에 포장지 / 어댑터를 언급했습니다. HTable에 일대일 복제본을 도입 할 필요는 없습니다. 물론 전체 프레임 워크는 물론 고통이 될 것입니다. 그러나 애플리케이션 영역과 HTable 영역 사이의 인터페이스 인 심이 필요합니다 . HTable의 일부 기능을 애플리케이션 자체 용어로 바꿔야합니다. 리포지토리 패턴은 데이터 액세스와 관련하여 이러한 이음새를 완벽하게 구현 한 것입니다.
guillaume31

11

철학적으로 모의를 사용하는 테스트는 실제 엔드 포인트를 사용하는 테스트보다 우선해야합니다.

나는 그것이 적어도 TDD 지지자들 사이 에서 현재 진행중인 논쟁 의 포인트라고 생각합니다 .

저의 개인적인 견해는 모의 기반 테스트가 대부분 인터페이스 계약 의 형태를 나타내는 방법이라고 말하는 것 이상입니다 . 인터페이스를 변경하는 경우에만 이상적으로 중단됩니다 (예 : 실패) . 따라서 Java와 같이 합리적으로 강력한 형식의 언어에서 명시 적으로 정의 된 인터페이스를 사용하는 경우 거의 완전히 불필요한 것입니다. 컴파일러는 인터페이스를 변경했는지 여부를 이미 알려줍니다.

주된 예외는 어노테이션 또는 리플렉션을 기반으로 매우 일반적인 인터페이스를 사용하는 경우 컴파일러가 유용하게 자동으로 경찰을 수행 할 수 없다는 것입니다. 그럼에도 불구하고 모의를 사용하는 것이 아니라 프로그래밍 방식으로 유효성 검사를 수행하는 방법이 있는지 확인해야합니다 (SQL 구문 검사 라이브러리).

'실시간'로컬 데이터베이스로 테스트 할 때 후자의 경우입니다. htable 구현은 손으로 작성하려고 생각했던 것보다 인터페이스 계약의 훨씬 포괄적 인 검증을 시작하고 적용합니다.

불행히도, 모의 기반 테스트의 훨씬 더 일반적인 사용은 다음과 같은 테스트입니다.

  • 테스트 작성 당시 코드가 무엇이든 통과
  • 코드의 존재 및 실행 유형 이외의 코드 속성에 대해서는 보증하지 않습니다.
  • 해당 코드를 변경할 때마다 실패

이러한 테스트는 당연히 삭제해야합니다.


1
이것을 충분히 백업 할 수 없습니다. 필자는 100pc 범위의 필러보다 훌륭한 테스트로 1pc 범위를 원합니다.
Ian

3
모의 기반 테스트는 실제로 2 개의 객체가 서로 대화하기 위해 사용하는 계약을 설명하지만 Java와 같은 언어의 유형 시스템이 할 수있는 것보다 훨씬 뛰어납니다. 메소드 서명뿐만 아니라 인수 또는 리턴 된 결과에 대해 유효한 값 범위를 지정할 수도 있습니다. 예외는 허용되며 예외는 몇 번이고 메소드를 호출 할 수있는 횟수 등이 있습니다. 컴파일러 만있는 경우 경고하지 않습니다. 그 변화입니다. 그런 의미에서 나는 그들이 불필요하다고 생각하지 않습니다. 모의 기반 테스트에 대한 자세한 내용은 infoq.com/presentations/integration-tests-scam 을 참조하십시오 .
guillaume31

1
... 인터페이스 호출에 대한 논리 테스트
Rob

1
확인되지 않은 예외, 선언되지 않은 전제 조건 및 암시 적 상태를 인터페이스를 덜 정적 인 유형으로 만드는 것의 목록에 추가 할 수 있으므로 간단한 컴파일 대신 모의 기반 테스트를 정당화 할 수 있습니다. 그러나 문제는 이러한 측면 변경 될 때 사양이 암시 적이며 모든 클라이언트의 테스트에 분산되어 있다는 것입니다. 업데이트되지 않을 가능성이 높으므로 녹색 진드기 뒤에 버그를 자동으로 숨기십시오.
soru

"그들의 사양은 암시 적이다": 인터페이스 ( blog.thecodewhisperer.com/2011/07/07/contract-tests-an-example )에 대한 계약 테스트를 작성 하고 모의를 설정할 때이를 준수 하지 않는 경우가 아닙니다 .
guillaume31

5

엔드 포인트 기반 테스트는 모의 기반 테스트보다 얼마나 오래 걸립니까? 훨씬 더 길다면, 단위 테스트를 더 빠르게하기 위해 테스트 작성 시간을 투자 할 가치가 있습니다. 여러 번 실행해야하기 때문입니다. 엔드 포인트 기반 테스트가 "순수한"단위 테스트가 아니더라도 단위 테스트가 제대로 수행되지 않는 한 더 오래 걸리지 않으면 종교적인 이유가 없습니다.


4

나는 guillaume31의 응답에 전적으로 동의하며, 소유하지 않은 유형을 조롱하지 마십시오!.

일반적으로 테스트의 고통 (복잡한 인터페이스를 조롱)은 디자인의 문제를 반영합니다. 아마도 모델과 데이터 액세스 코드 사이에 추상화가 필요할 것입니다. 육각형 아키텍처를 사용하는 예제와 이러한 종류의 문제를 해결하는 가장 일반적인 방법은 리포지토리 패턴입니다.

작업을 확인하기 위해 통합 테스트를 수행하려면 통합 테스트를 수행하고 논리를 테스트하기 때문에 단위 테스트를 수행하려는 경우 단위 테스트를 수행하고 지속성을 분리하십시오. 그러나 통합 테스트는 외부 시스템에서 로직을 분리하는 방법을 모르거나 (고통을 격리시키기 때문에) 큰 냄새가 나기 때문에 실제 요구가 아닌 설계 제한을 위해 단위를 통해 통합을 선택하고 있습니다. 통합을 테스트합니다.

Ian cooper : http://vimeo.com/68375232 이 대화 양식을 살펴보십시오. 그는 육각형 아키텍처 및 테스트에 대해 이야기하고, 언제 그리고 무엇을 조롱해야하는지에 대해 이야기합니다. .


1

TL; DR- 내가 보는 방식은 테스트에 소요되는 노력의 양과 실제 시스템에 더 많은 시간을 투자하는 것이 더 나은지 여부에 달려 있습니다.

긴 버전 :

여기에 몇 가지 좋은 답변이 있지만 그에 대한 내 견해는 다릅니다 : 테스트는 스스로 돈을 갚아야하는 경제 활동이며, 지출 한 시간이 개발 및 시스템 신뢰성 (또는 다른 것으로 보이는 것)으로 돌아 가지 않으면 그런 다음 당신은 나쁜 투자를하고있을 수 있습니다; 테스트를 작성하지 않고 시스템을 구축해야합니다. 따라서 테스트 작성 및 유지 노력을 줄이는 것이 중요합니다.

예를 들어, 테스트에서 얻는 주요 가치는 다음과 같습니다.

  • 신뢰성 (및 개발 속도) : 코드 리팩터링 / 새 프레임 워크 통합 / 구성 요소 / 포트를 다른 플랫폼으로 교체, 여전히 작동 함을 확신
  • 설계 피드백 : 저급 / 중급 인터페이스에서 클래식 TDD / BDD "코드 사용"피드백

라이브 엔드 포인트에 대한 테스트는 여전히이를 제공해야합니다.

라이브 엔드 포인트에 대한 테스트의 몇 가지 단점 :

  • 환경 설정-테스트 실행 환경을 구성하고 표준화하는 것이 더 많은 작업이며 미묘하게 다른 환경 설정으로 인해 미묘하게 다른 동작이 발생할 수 있습니다
  • Statelessness-라이브 엔드 포인트에 대한 작업은 연약한 엔드 포인트 상태에 의존하는 쓰기 테스트를 촉진 할 수 있습니다.
  • 테스트 실행 환경은 취약합니다. 테스트에 실패하면 테스트, 코드 또는 라이브 엔드 포인트입니까?
  • 실행 속도-라이브 엔드 포인트는 일반적으로 느리고 때로는 병렬화하기가 더 어렵습니다.
  • 테스트를위한 엣지 케이스 작성-일반적으로 모의에 사소한, 때로는 라이브 엔드 포인트에 대한 고통 (예 : 설정하기 까다로운 것은 전송 / HTTP 오류)

이 상황에 있었는데 단점이 문제가되지 않았지만 엔드 포인트를 조롱하면 테스트 작성 속도가 상당히 느려졌다면, 확신이있는 한 하트 비트로 라이브 엔드 포인트에 대해 테스트했습니다. 잠시 후에 다시 확인하여 단점이 실제로 문제가되지 않는지 확인하십시오.


1

테스트 관점에서 반드시 요구되는 몇 가지 요구 사항이 있습니다.

  • 테스트 (단위 또는 기타)는 생산 데이터를 만질 수있는 방법이 없어야합니다.
  • 한 테스트 결과는 다른 테스트 결과에 영향을 미치지 않아야합니다.
  • 항상 알려진 위치에서 시작해야합니다

테스트 외부의 상태를 유지하는 모든 소스에 연결할 때 큰 도전입니다. TDD는 "순수한"것은 아니지만 Ruby on Rails 승무원은 사용자의 목적에 맞게 조정될 수있는 방식으로이 문제를 해결했습니다. 레일즈 테스트 프레임 워크는 다음과 같이 작동했습니다.

  • 단위 테스트를 실행할 때 테스트 구성이 자동으로 선택되었습니다
  • 단위 테스트 실행 시작시 데이터베이스가 작성 및 초기화되었습니다.
  • 단위 테스트가 실행 된 후 데이터베이스가 삭제되었습니다.
  • SqlLite를 사용하는 경우 테스트 구성에서 RAM 데이터베이스를 사용했습니다.

이 모든 작업은 테스트 하니스에 내장되어 있으며 합리적으로 잘 작동합니다. 더 많은 것이 있지만 기본 사항 으로이 대화에 충분합니다.

시간이 지남에 따라 함께 일한 다른 팀에서는 코드가 가장 정확한 경로가 아니더라도 테스트를 촉진 하도록 선택할 수 있습니다. 이상적으로는 제어 된 코드로 모든 호출을 데이터 저장소로 래핑합니다. 이론적으로, 이러한 오래된 프로젝트 중 하나가 새로운 자금을 확보 한 경우, 소수의 클래스에만 관심을 집중시켜 데이터베이스 바인딩에서 Hadoop 바인딩으로 전환 할 수 있습니다.

중요한 측면은 프로덕션 데이터를 망쳐 놓지 말고 실제로 테스트하고 있다고 생각하는 것을 테스트하고 있는지 확인하십시오. 외부 서비스를 요청시 알려진 기준으로, 심지어 코드에서도 재설정 할 수 있어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.