2009-07-10 4 views
12

나는 NMock2를 사용하고, 나는 몇 가지 일반적인 모의 프레임 워크의 개념을 표현하기 위해 다음과 같은 NMock 클래스 초안을 작성했습니다언제 예상하고 언제 스텁을합니까?

  • Expect을 : 이것은 조롱 방법은 반환해야합니다을 지정하고 통화 테스트 발생하거나해야한다고 말한다 실패 (VerifyAllExpectationsHaveBeenMet() 전화가 수반되는 경우).

  • Stub : 조롱 된 메소드가 리턴해야하는 것은 지정하지만 테스트가 실패 할 수는 없습니다.

그럼 언제해야합니까?

+0

스텁이 지정한 내용을 반환하는 동안 Expect는 Nothing을 반환합니다. 양쪽 모두 '스텁 (stub)'한 번 사용 방법이 좋은 경우에 대해서는 – zinking

답변

15

프레임 워크들이 기능적으로 고려 될 수있는 지점에 가까이 함께 & & 스텁 가까운 모의 객체의 개념을 가져오고 있습니다 조롱의 많은 거의 같다.

  • 모의 :하지만 개념적인 관점에서, 나는 보통이 규칙을 따르려고 명시 적으로 테스트중인 객체의 동작을 검증하려고하는 경우에만 (즉, 테스트는이 개체를 호출해야 함을 말하고있다 그 객체).
  • 스텁: 일부 기능/동작을 테스트하려고하지만 일부 외부 객체에 의존해야하는 경우 (즉,이 객체가 무언가를해야한다는 테스트가 있습니다. 효과, 그것은 그 개체를 호출 할 수 있습니다)

이것은 각 단위 테스트가 한 가지를 테스트 할 때 분명 해집니다. 물론 한 번의 테스트에서 모든 것을 테스트하려고한다면 모든 것을 기대할 수 있습니다. 그러나 특정 단위 테스트가 검사하는 항목 만 예상하면 코드의 목적이 무엇인지 한눈에 알 수 있으므로 코드가 훨씬 명확 해집니다.

또 다른 이점은 변경으로부터 약간 더 격리된다는 것입니다. & 변경으로 인해 휴식이 발생할 때 더 좋은 오류 메시지가 표시됩니다. 다시 말해, 구현의 일부분을 변경하면 테스트 케이스가 하나만 남을 가능성이 커지고, 노이즈가 발생하는 &을 깨뜨리는 일련의 테스트가 아니라 파손 된 부분이 정확히 표시됩니다.

편집 : 계산기 객체 (의사 코드) 데이터베이스에 대한 모든 추가 사항을 감사 곳은 ... 인위적인 예에 ​​따라 명확하게 수있는 첫 번째 테스트 케이스에 따라서

public void CalculateShouldAddTwoNumbersCorrectly() { 
    var auditDB = //Get mock object of Audit DB 
    //Stub out the audit functionality... 
    var calculator = new Calculator(auditDB); 
    int result = calculator.Add(1, 2); 
    //assert that result is 3 
} 

public void CalculateShouldAuditAddsToTheDatabase() { 
    var auditDB = //Get mock object of Audit DB 
    //Expect the audit functionality... 
    var calculator = new Calculator(auditDB); 
    int result = calculator.Add(1, 2); 
    //verify that the audit was performed. 
} 

우리 Add 메서드 &의 기능을 테스트 할 때 감사 이벤트가 발생하는지 여부는 신경 쓰지 않지만 계산기가 auditDB 참조와 함께 작동하지 않는다는 것을 알고 우연히 최소값을 제공하도록 스텁합니다 특정 테스트 케이스가 작동하도록하는 기능을 제공합니다.두 번째 테스트에서는 특별히 Add을 수행 할 때 감사 이벤트가 발생하므로 테스트를 수행하지 않기 때문에 감사 이벤트가 발생하므로 여기에 기대치를 사용합니다 (결과가 무엇인지 상관하지 않음).

예, 두 사례를 하나로 결합하여 & 기대를하고 결과가 3이라고 주장 할 수 있지만 한 단위 테스트에서 두 가지 사례를 테스트 중입니다. 이렇게하면 테스트가 더 부서지기 쉽습니다 (테스트를 중단하기 위해 변경 될 수있는 사물의 표면적이 더 커지기 때문에). 그리고 병합 테스트가 실패 할 때 즉시 문제가 무엇인지 알 수 없으므로 추가 기능이 작동하지 않습니다. 또는 감사가 작동하지 않습니까?)

+0

다른 조롱하는 프레임 워크와는 어떻게 다른지 모르겠지만, NMock을 사용하면 하나의 기대를 확인하기 시작하면 모든 외부 호출이 끊어 지므로 때로는 부담이됩니다. 이 요구 사항으로 인해 더 나은 설계가 가능하다는 것을 알게되었지만 대부분의 경우 이전에 많은 리팩토링을 수행 할 여유가없는 레거시 코드에 대한 단위 테스트를 작성해야합니다. –

+2

흠 ... 그 때 차이가 있습니다. 저는 주로 RhinoMocks를 사용했습니다. RhinoMocks는 한 가지 방법을 기대 한 다음 다른 것을 스텁하는 데 사용할 수 있습니다. 내 포인트는 여전히 많이 있지만 (내 추가 예제 참조), 귀하의 경우에는 한 번의 테스트에서 모든 기대 기반 테스트 (즉, 행동 테스트)를 수행해야합니다. – Alconja

+0

Ack, 내가 명확히해야합니다 (그리고 내 질문의 본문에서 이것을 언급 할 수도 있습니다) : NMock에서도 예상치와 스텁을 혼합 할 수 있습니다. 문제는 종종 나머지를 스텁하지 않아도되는 하나의 Expectation을 지정하고 싶다는 것입니다. (다시 말하지만, 특히 솔리드가 좋은 아키텍처를 사용할 수있는 코드를 처리 할 때 특히 그렇습니다. 외부 통화 레이어). 오, +1. –

1

음 ... 이건 더 간단 할 수 없습니다. 테스트에서 발표자가 저장을 호출하는지 테스트하는 경우 예상을 수행하십시오. Save (저장)가 중지되면 발표자가 예외를 정상적으로 처리 할 수 ​​있는지 테스트가 필요한 경우 스텁을 수행하십시오.

자세한 내용은

, this podcast by Hanselman and Osherove (단위 테스트의 예술의 저자)를 확인

+0

+1입니다. 매우 좁은 편이지만 질문은 여전히 ​​더 간단 할 수 있습니다. –

+0

좋아. 당신이 주장한다면 나는 아기 피드 것입니다 :) 단위 테스트는 한 가지만 테스트해야합니다. 두 가지. SUT (System Under Test)가 종속성 중 하나에 적절한 조치를 위임하는지 여부를 테스트해야합니다. 또는 SUT가 종속성에 의해 반환 된 결과에 올바르게 반응하는지 테스트해야합니다. 먼저 Mock을 사용하십시오. 두 번째 경우 스텁을 사용하십시오. 의심스러운 경우 Diamond of Jacks를 사용하십시오. – zvolkov

4

"예상되는 작업, 스텁 쿼리". 호출이 테스트 대상 외부의 세계 상태를 변경해야한다면 기대하는 것입니다. 호출 방법에 대해 신경을 써야합니다. 단지 쿼리 일 경우 시스템 상태를 변경하지 않고 한 번 또는 6 번 호출 한 다음 호출을 스텁 할 수 있습니다.

한 가지 더 알아 두어야 할 점은 스텁과 기대, 즉 전체 호출이 아니라 개별 호출이라는 점입니다.