모의와 스터브의 차이점은 무엇입니까?


962

Martin Fowler의 Mocks Are n't Stubs를 포함하여 테스트에서 조롱과 스터 빙에 대한 다양한 기사를 읽었 지만 여전히 차이점을 이해하지 못합니다.



75
@OP 차이가 없기 때문에. 이 기사는 커뮤니티가 사랑하는만큼 이해하기 쉬운 단어에 의미를 더하고 불필요한 것을 복잡하게함으로써 불필요한 혼란을 낳습니다. 모의는 실물이 아닌 가짜 비즈니스 로직을 실행하는 모의 일뿐입니다. 결국 행동을 확인하는 것이 당신의 선택이지만 여전히 모의입니다. 또는 당신이 그것을 부르고 싶지만 그것을 하나 만드십시오. 머리카락을 나누지 마십시오. 사람들이 당신의 개념을 쉽게 이해할 수 있도록 간단하게 유지하십시오.
wst

10
"모의, 가짜, 스텁 사이의 분류는 문헌에서 매우 일치하지 않습니다." 많은 인용. 여전히 내가 가장 좋아하는 Wikipedia 인용구 중 하나-존재하는 경우 :) en.wikipedia.org/wiki/Mock_object
JD.

11
Martin Fowler의 기사는 초보자에게는 이해하기 어렵습니다.
lmiguelvargasf 2016

1
내가 이해하는 방식은 스텁이 더미 데이터 수집과 같이 테스트를위한 버려진 객체 일뿐이라는 것입니다. Mock은 테스트를 위해 동작이 변경되었을 수있는 다양한 방법을 가진 서비스 계층과 같이보다 복잡한 것의 영리하게 재정의 된 버전입니다. 스터 빙 된 물체를 모의 레이어에 전달할 수있는 것처럼 두 가지가 함께 사용됩니다.
JsonStatham 2016 년

답변:


746

그루터기

가장 큰 차이점은 미리 정해진 행동으로 작성한 스텁입니다. 따라서 테스트 목적으로 가짜 인 의존성 (추상 클래스 또는 인터페이스)을 구현하는 클래스가 있으며 설정된 응답으로 메소드가 스텁 아웃됩니다. 그들은 멋진 일을하지 않을 것이며 이미 테스트 외부에서 스텁 된 코드를 작성했을 것입니다.

모조품

모의는 테스트의 일부로 기대치로 설정해야하는 것입니다. 모의는 미리 정해진 방식으로 설정되지 않았으므로 테스트에서 수행하는 코드가 있습니다. 예상치를 설정하는 코드는 작업을 수행하기 전에 실행해야하므로 런타임에 mocks가 결정됩니다.

Mocks와 Stubs의 차이점

모의로 작성된 테스트는 일반적 initialize -> set expectations -> exercise -> verify으로 테스트 패턴을 따릅니다 . 미리 작성된 스텁은initialize -> exercise -> verify .

Mocks와 Stubs의 유사성

두 가지의 목적은 클래스 또는 함수의 모든 종속성 테스트를 제거하여 테스트하려는 항목에 더 집중하고 단순하게 테스트하는 것입니다.


876

머리말

실제가 아닌 객체에 대한 몇 가지 정의가 있습니다. 일반적인 용어는 test double 입니다. 이 용어는 더미 , 가짜 , 스터브 , 모의 됩니다.

참고

Martin Fowler의 기사 에 따르면 :

  • 더미 객체는 전달되지만 실제로는 사용되지 않습니다. 일반적으로 매개 변수 목록을 채우는 데 사용됩니다.
  • 가짜 객체는 실제로 작동하는 구현이 있지만 일반적으로 생산에 적합하지 않은 바로 가기를 사용합니다 (메모리 데이터베이스가 좋은 예입니다).
  • 스텁 은 일반적으로 테스트를 위해 프로그래밍 된 외부의 항목에는 전혀 응답하지 않는 테스트 중에 호출에 대해 미리 준비된 답변을 제공합니다. 스텁은 '보낸'메시지를 기억하는 전자 메일 게이트웨이 스텁 또는 '보낸'메시지 수와 같은 통화에 대한 정보를 기록 할 수도 있습니다.
  • Mocks 는 우리가 여기서 말하는 것입니다. 기대되는 사전 프로그래밍 된 객체는 그들이받을 전화의 사양을 형성합니다.

스타일

Mocks vs Stubs = 행동 테스트 대 상태 테스트

원리

테스트 원칙에 따라 테스트 당 한 가지만 에는 여러 개의 스터브가있을 수 있지만 일반적으로 하나의 모의가 있습니다.

라이프 사이클

스텁을 사용하여 수명주기를 테스트하십시오.

  1. 설정-테스트중인 오브젝트 및 스텁 협업자를 준비하십시오.
  2. 연습-기능을 테스트합니다.
  3. 상태 확인-assert를 사용하여 오브젝트의 상태를 확인하십시오.
  4. 철거-리소스 정리

모의 테스트 라이프 사이클 :

  1. 설정 데이터-테스트중인 개체를 준비합니다.
  2. 설치 기대치 -기본 오브젝트에서 사용중인 모의 예상치를 준비하십시오.
  3. 연습-기능을 테스트합니다.
  4. 기대치 확인 -모의에서 올바른 메소드가 호출되었는지 확인하십시오.
  5. 상태 확인-assert를 사용하여 오브젝트의 상태를 확인하십시오.
  6. 철거-리소스 정리

요약

모의 테스트와 스텁 테스트 모두 질문에 대한 답변을 제공합니다 . 결과는 무엇입니까?

모의 테스트도 관심이 있습니다 : 결과는 어떻게 달성 되었습니까?


잠깐, 조롱도 통조림 답변을 반환합니까? 그렇지 않으면 왜 그들이 질문에 대답합니까?
AturSams

당신이 쓴 것에서 mocks = stubs + expects and verifys를 알 수 있습니다. 왜냐하면 mocks는 "테스트 동안 작성된 통조림에 대한 통조림 된 답변을 제공합니다. 그리고 파울러가 그루터기의 예로써 보여준 예는 실제로 스파이의 예입니다! 그것은 모의가 그루터기이고, 스파이는 그루터기라는 것을 의미합니다. 스텁은 여러 작업 방법이있는 객체 일뿐입니다. 또한 Mockito가 stub () 메소드를 더 이상 사용하지 않는 이유를 설명합니다.
kolobok

내가 혼란스럽게 생각하는 것은 이것과 "정답 설정"입니다. 무슨 의미입니까? 일반적으로 "메인 코드"에서는 예상 한 결과를 만듭니다. 그래도 기대치를 모의 객체에 넣은 것처럼 들리지만 나에게는 의미가 없습니다. 또한 입력만으로 모의를 쉽게 연습하고 결과를 저장하고 나중에 "예상"을 만든 다음 비교할 수 있습니다. 내가 너무 추상적이고 모호한 용어를 사용합니다.
IceFire

365

스텁은 단순한 가짜 개체입니다. 테스트가 순조롭게 진행되도록합니다.
모의는 더 똑똑한 스텁입니다. 테스트가 통과했는지 확인합니다.


33
나는 이것이 가장 간결하고 정답이라고 생각합니다. 테이크 아웃 : 모의 IS-A 스텁. stackoverflow.com/a/17810004/2288628 이이 답변의 더 긴 버전입니다.
PoweredByRice

8
나는 모의가 스텁이라고 생각하지 않습니다. Mocks는 데이터를 주장하는 데 사용되며 데이터를 반환해서는 안되며, 스텁은 데이터를 반환하는 데 사용되며 절대로 주장해서는 안됩니다.
dave1010

2
@ dave1010 Mocks는 가장 확실하게 데이터를 반환하거나 예외를 던질 수 있습니다. 그들은 그들에게 전달 된 매개 변수에 응답하여 그렇게해야합니다.
트 렌턴

2
객체 반환 또는이 다음에 전달 된 데이터를 기반으로 던졌습니다 @trenton 경우는 A의 가짜 아닌 가짜. 스텁은 SUT가 메시지 수신을 처리하는 방법을 테스트하고 SUT가 메시지를 보내는 방법을 테스트 합니다. 2를 섞으면 OO 디자인이 나빠질 수 있습니다.
dave1010

8
나는 이것이 훌륭하다고 생각합니다-그루터기는 질문에 대한 답을 돌려줍니다. 모의은 또한 질문에 대한 답변을 반환하지만 질문이 요청되었음을 확인합니다 !!
Leif

238

다음은 실제 샘플과 함께 각각에 대한 설명입니다.

  • 더미 -단지 가짜 값을 만족시킵니다 API.

    예제 : 테스트에 영향미치지 않는 생성자에 많은 필수 매개 변수가 필요한 클래스의 메서드를 테스트하는 경우 클래스 의 새 인스턴스를 만들기 위해 더미 객체를 만들 수 있습니다.

  • 모조품 -일부 외부 인프라에 종속 될 수있는 클래스의 테스트 구현을 작성하십시오. 단위 테스트가 실제로 외부 인프라와 상호 작용 하지 않는 것이 좋습니다 .

    : 데이터베이스에 액세스하기 위해 가짜 구현을 작성하십시오.in-memory 컬렉션으로 .

  • 그루터기 - 재정의 방법은 하드 코딩 된 값이라고도을 반환합니다 state-based.

    : 테스트 수업은 Calculate()완료 하는 데 5 분이 걸리는 방법에 따라 다릅니다 . 5 분 동안 기다리지 않고 실제 구현을 하드 코딩 된 값을 반환하는 스텁으로 바꿀 수 있습니다. 시간의 작은 부분 만 차지합니다.

  • 모조품 - 매우 유사 Stub하지만, interaction-based오히려 상태 기반보다. 이것은 Mock어떤 값을 반환하지는 않지만 특정 순서의 메소드 호출이 있다고 가정한다는 것을 의미합니다 .

    예 : 사용자 등록 클래스를 테스트하고 있습니다. 를 호출 한 후에 SaveSendConfirmationEmail .

StubsMocks의 하위 유형 실제로 Mock, 테스트 구현 모두 스왑 실제 구현하지만 다른에 대한 구체적인 이유는.


175

에서 codeschool.com의 과정, 레일 테스트 좀비에 대한 , 그들은 용어의 정의를 제공합니다 :

그루터기

지정된 결과를 리턴하는 코드로 메소드를 대체합니다.

모조품

메소드가 호출되는 주장이있는 스텁.

Sean Copenhaver가 그의 답변에서 설명했듯이, 차이점은 모의가 기대치를 설정한다는 것입니다 (즉, 호출 여부와 방법에 대한 주장을합니다).


Dillon post를 보완하기 위해 우유, 계란, 설탕, 오븐과 같은 여러 라이브러리를 사용하는 "MakeACake"라는 클래스가 있습니다.
aarkerio

139

스텁은 테스트에 실패하지 않습니다.


2
리팩토링 후 테스트가 동일한 동작을하는지 알고 있습니다.
RodriKing

1
@RodriKing 같은 느낌이 듭니다. Mock과 마찬가지로 프로덕션 코드가 변경되면 테스트 코드도 변경됩니다. 어느 것이 고통입니까! 스텁을 사용하면 동작을 계속 테스트하는 것처럼 느껴지므로 테스트 코드로 미세 변경을 수행 할 필요가 없습니다.
tucq88

35

이 질문에 대한 가장 간단하고 명확한 대답은 Roy Osherove 가 그의 저서 The Unit of Art Testing (85 페이지)에서 제공 한 것 같습니다.

스텁을 처리하는 가장 쉬운 방법은 스텁이 테스트에 실패하지 않을 수 있다는 것입니다. 테스트에서 사용하는 어설 션은 항상 테스트중인 클래스에 대한 것입니다.

반면에 테스트는 모의 객체를 사용하여 테스트가 실패했는지 여부를 확인합니다. [...]

다시 모의 객체는 테스트 실패 여부를 확인하는 데 사용하는 객체입니다.

즉, 가짜에 대해 어설 션을 작성하는 경우 가짜를 모의로 사용하고 있다는 것을 의미합니다. 가짜를 사용하여 테스트를하지 않고 테스트를 실행하는 경우 가짜를 스텁으로 사용하고 있습니다.


2
귀하의 답변이 정상에 도달하기를 바랍니다. 이 youtu.be/fAb_OnooCsQ?t=1006을 설명하는 R. Osherove 입니다.
Michael Ekoka

31

위의 모든 설명을 읽고 응축하려고합니다.

  • 스텁 (Stub) : 테스트를 실행할 수있게하는 더미 코드 조각이지만, 그 결과는 상관 없습니다.
  • 모의 : 테스트의 일부로 VERIFY가 올바르게 호출되는 더미 코드 조각.
  • Spy : 실제 코드 조각에 대한 일부 호출을 가로 채어 전체 원본 개체를 바꾸지 않고도 호출을 확인할 수있는 더미 코드 조각입니다.

4
좋은 대답입니다. Mock은 정의에 따라 Spy와 매우 유사하게 들립니다. 테스트 복식을 몇 개 더 포함하도록 답변을 업데이트하면 좋을 것입니다.
Rowan Gontier

이 답변을 쓸 때 스파이에 대해 들어 보지 못했습니다.
O'Rooney

23

모의는 행동을 테스트하고 특정 방법이 호출되도록합니다. 스텁은 특정 객체의 테스트 가능한 버전 (자체)입니다.

애플 방식이란 무엇입니까?


19
"Apple 방식이란 무엇입니까?" 사용 헬 베티
쿠비

7
마이크로 소프트와는 반대로 애플 방식으로 :)
never_had_a_name

2
이것이 상황에 도움이됩니까?
NebulaFox

21

디버깅과 비교하면 :

스텁 은 메소드가 올바른 값을 리턴하는지 확인하는 것과 같습니다.

Mock 은 실제로 메소드에 들어가서 올바른 값을 반환하기 전에 내부의 모든 것이 올바른지 확인 하는 것과 같습니다 .


20

정신 모델을 사용하면 실제로 "싱크"하지 않은 모든 설명과 기사가 아니라 이것을 이해하는 데 실제로 도움이되었습니다.

당신의 아이가 테이블 위에 유리판을 가지고 있고 그것을 가지고 놀고 있다고 상상해보십시오. 자, 당신은 그것이 깨질 것을 두려워합니다. 그래서 당신은 그에게 대신 플라스틱 접시를 제공합니다. 그것은 모의 일 것이다 (같은 행동, 동일한 인터페이스, "더 부드러운"구현).

이제 플라스틱 교체품이 없다고 말하고 "계속 재생하면 고장납니다!"라고 설명합니다. 그것은 Stub 입니다. 사전에 미리 정의 된 상태를 제공했습니다.

더미는 그는 심지어 사용하지 않은 분기점이 될 것입니다 ... 그리고 스파이는 이미 일한 사용되는 것과 동일한 설명을 제공하는 같은 수 있습니다.


19

그들 사이의 가장 중요한 차이점은 그들의 의도라고 생각합니다.

왜 스텁왜 모의 에서 설명하려고

Mac Twitter 클라이언트의 공개 타임 라인 컨트롤러 용 테스트 코드를 작성한다고 가정합니다.

테스트 샘플 코드는 다음과 같습니다.

twitter_api.stub(:public_timeline).and_return(public_timeline_array)
client_ui.should_receive(:insert_timeline_above).with(public_timeline_array)
controller.refresh_public_timeline
  • STUB : Twitter API에 대한 네트워크 연결이 너무 느려서 테스트 속도가 느려집니다. 타임 라인을 반환한다는 것을 알고 있으므로 HTTP twitter API를 시뮬레이션하는 스텁을 만들었으므로 테스트가 매우 빠르게 실행되며 오프라인에서도 테스트를 실행할 수 있습니다.
  • MOCK : UI 메서드를 아직 작성하지 않았으며 ui 객체에 어떤 메서드를 작성해야하는지 잘 모르겠습니다. 테스트 코드를 작성하여 컨트롤러가 ui 객체와 어떻게 협업하는지 알고 싶습니다.

모의를 작성하면 예상이 충족되는지 확인하여 오브젝트 협업 관계를 발견하는 한편 스텁은 오브젝트의 동작 만 시뮬레이션합니다.

모의에 대해 더 많이 알고 싶다면이 기사를 읽으십시오 : http://jmock.org/oopsla2004.pdf


1
나는 당신이 옳은 생각을 가지고 있다고 생각하지만 Dillon Kearns는 그것을 더 명확하게 설명했습니다.
O'Rooney

19

매우 명확하고 실용적입니다.

스텁 : 위조 될 클래스 / 객체의 메소드를 구현하고 항상 원하는 것을 반환하는 클래스 또는 객체.

JavaScript의 예 :

var Stub = {
   method_a: function(param_a, param_b){
      return 'This is an static result';
   }
}

모의 : 스텁과 동일하지만 메소드가 호출 될 때 "확인"하는 로직을 추가하므로 일부 구현이 해당 메소드를 호출하는지 확인할 수 있습니다.

@mLevan이 말했듯이 사용자 등록 클래스를 테스트하고 있다고 예를 들어보십시오. 저장을 호출 한 후 SendConfirmationEmail을 호출해야합니다.

매우 어리석은 코드 예 :

var Mock = {
   calls: {
      method_a: 0
   }

   method_a: function(param_a, param_b){
     this.method_a++; 
     console.log('Mock.method_a its been called!');
   }
}

16

이 슬라이드는 주요 차이점을 매우 잘 설명합니다.

여기에 이미지 설명을 입력하십시오

* 워싱턴 대학교 CSE 403 16 강 ( "Marty Stepp"이 만든 슬라이드)


이것은 두 IMO 간의 차이점에 대한보다 명확한 설명입니다. 스텁 : 테스터가 스텁을 가져와 테스트중인 클래스 내에서 직접 사용하십시오. 그러나 Mock의 경우 테스터는 Mock 객체가 사용되는 방식을 장치해야합니다. 다른 경우에는 다르게 동작합니다. 대조적으로, 스터브는 다르게 동작 할 것으로 예상되지 않지만 그대로 사용됩니다 (접촉 할 때마다 동일한 데이터를 반환 함을 의미 함)
Dexter

12

Roy Osherove [비디오 링크] 의 설명이 마음에 듭니다 .

생성 된 모든 클래스 또는 객체는 가짜입니다. 당신이 그것에 대해 전화를 확인하면 그것은 모의입니다. 그렇지 않으면 스텁입니다.


12
  • 스텁 스
    • 스텁
      1. 메소드 호출에 대한 특정 답변 제공
        • 예 : myStubbedService.getValues ​​()는 테스트중인 코드에 필요한 문자열을 반환합니다.
      2. 테스트중인 코드에서이를 격리하는 데 사용
      3. 테스트 실패
        • 예 : myStubbedService.getValues ​​()는 스텁 된 값만 반환합니다.
      4. 종종 추상 메소드를 구현
    • 목신
      1. 스텁의 "슈퍼 셋"; 특정 메소드를 호출 할 수 있음
        • 예 : myMockedService.getValues ​​()가 한 번만 호출되는지 확인
      2. 테스트중인 코드의 동작을 테스트하는 데 사용
      3. 테스트 실패
        • 예 : myMockedService.getValues ​​()가 한 번 호출되었는지 확인하십시오. 테스트 한 코드에서 myMockedService.getValues ​​()를 호출하지 않았으므로 확인이 실패합니다.
      4. 종종 인터페이스를 조롱

11

테스트 복식을 보자 :

  • 가짜 : 가짜는 실제 구현이 있지만 프로덕션과 동일하지 않은 객체입니다. 같은 : 데이터 액세스 개체 또는 저장소의 메모리 구현입니다.
  • 스텁 : 스텁은 사전 정의 된 데이터를 보유하고 테스트 중에 호출에 응답하는 데 사용하는 객체입니다. 같은 : 메서드 호출에 응답하려면 데이터베이스에서 일부 데이터를 잡아해야하는 객체입니다.

  • Mocks : Mocks는 수신 통화를 등록하는 객체입니다. 테스트 어설 션에서 Mocks에서 모든 예상 작업이 수행되었는지 확인할 수 있습니다. 등의 서비스를 보내는 전자 메일을 호출하는 기능 :. 자세한 내용은 이것을 확인 하십시오 .


1
내 의견으로는 최고의 답변
에로 스테파노

9

가짜 실제 개체 같은 사람들 때문에 모두보기, 스텁 또는 모의 객체 (필기 또는 기타) 중 하나를 설명하는 데 사용 될 수있는 일반적인 용어이다.

가짜가 스텁인지 모의인지는 현재 테스트에서 사용되는 방법에 따라 다릅니다. 상호 작용을 확인하는 데 사용되는 경우 (모의 대상) 모의 객체입니다. 그렇지 않으면 스텁입니다.

가짜 는 테스트가 원활하게 진행되도록합니다. 이는 미래의 테스트 독자가 외부 코드에 의존하지 않고 소스 코드를 읽을 필요없이 가짜 객체의 동작을 이해할 것임을 의미합니다.

테스트 실행이 원활하게 무엇을 의미합니까?
아래 코드의 예 :

 public void Analyze(string filename)
        {
            if(filename.Length<8)
            {
                try
                {
                    errorService.LogError("long file entered named:" + filename);
                }
                catch (Exception e)
                {
                    mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror");
                }
            }
        }

mailService.SendEMail () 메소드 를 테스트하려고합니다. 테스트 메소드에서 예외를 시뮬레이트해야하므로 가짜 스텁 errorService 클래스를 작성하여 해당 결과를 시뮬레이트하면 테스트 코드에서 테스트 할 수 있습니다. mailService.SendEMail () 메소드. 보시다시피 다른 외부 종속성 ErrorService 클래스의 결과를 시뮬레이션해야합니다.


8

jMock 개발자가 작성한 Objects가 아닌 Mock Roles 논문에서 바로 :

스텁은 미리 작성된 결과를 리턴하는 프로덕션 코드의 더미 구현입니다. 모의 객체는 스텁 역할을하지만 대상 객체와 해당 이웃의 상호 작용을 계측하기위한 어설 션도 포함합니다.

따라서 주요 차이점은 다음과 같습니다.

  • 스텁에 설정된 기대치는 일반적으로 일반적이지만 모의에 설정된 기대는 더 "영리한"일 수 있습니다 (예 : 첫 번째 호출에서 이것을 반환하고 두 번째 호출에서 이것을 반환합니다).
  • 스터브 는 주로 SUT의 간접 입력설정 하는 데 사용되는 반면 모의SUT의 간접 입력과 간접 출력을 모두 테스트 하는 데 사용할 수 있습니다 .

요약하자면 Fowler의 기사 제목 에서 혼란을 해소하려고 시도하는 동안 모의는 스텁이지만 스텁은 아닙니다 .


1
나는 당신이 옳다고 생각하지만, 이것이 파울러 기사가 혼란스러워하는 이유입니다. 기사 제목은 "Mocks Are n't Stubs"입니다. ¯_ (ツ) _ / ¯
stonedauwg

@stonedauwg, 실제로, 나는 당신의 말장난과 설명을 포함하도록 게시물을 편집했습니다. 이것이 조금 더 도움이되기를 바랍니다.
Dimos

@stonedauwg, 모의는 사각형이 아닌 스텁이 아닙니다. :)
seanriordan08

7

나는 The Unit of Unit Testing 을 읽고 있었고 다음과 같은 정의를 우연히 발견했습니다.

가짜는 실제 개체 같은 사람들 때문에 모두보기, 스텁 또는 모의 객체 (필기 또는 기타) 중 하나를 설명하는 데 사용 될 수있는 일반적인 용어이다. 가짜가 스텁인지 모의인지는 현재 테스트에서 사용되는 방법에 따라 다릅니다. 상호 작용을 확인하는 데 사용되는 경우 ( 모의 대상) 모의 객체 입니다. 그렇지 않으면 스텁 입니다.


5

UncleBob The Little Mocker 의이 흥미로운 기사를 보았습니다 . 모든 용어를 이해하기 쉬운 방식으로 설명하므로 초보자에게 유용합니다. Martin Fowlers 기사는 저와 같은 초보자에게 특히 어려운 기사입니다.


4

스텁 은 테스트 실행에 도움이됩니다. 어떻게? 테스트 실행에 도움이되는 값을 제공합니다. 이 값 자체는 실제 값이 아니며 테스트를 실행하기 위해 이러한 값을 만들었습니다. 예를 들어 데이터베이스 테이블의 값과 유사한 값을 제공하기 위해 HashMap을 만듭니다. 따라서 데이터베이스와 직접 상호 작용하는 대신 Hashmap과 상호 작용합니다.

모의 는 테스트를 실행하는 가짜 개체입니다. 우리가 주장하는 곳에


"따라서 데이터베이스와 직접 상호 작용하는 대신 Hashmap과 상호 작용합니다." ... 아직 데이터베이스 모듈을 코딩 할 시간이 없었기 때문에 스텁을 사용하지 않고 테스트 코드를 실행할 수 없었습니다. 그렇지 않으면 매우 동일한 Hasmap이 모의가 될 것입니다! 권리?
Boris Däppen

4

C # 및 Moq 프레임 워크를 사용하는 모의 대 스터브 예는 아래를 참조하십시오. Moq에는 Stub에 대한 특별한 키워드가 없지만 Mock 객체를 사용하여 스텁도 만들 수 있습니다.

namespace UnitTestProject2
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Moq;
    [TestClass]
    public class UnitTest1
    {
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));

            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
        }
        /// <summary>
        /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
        {
            // Arrange 
            var mockEntityRepository = new Mock<IEntityRepository>();
            mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
            var entity = new EntityClass(mockEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(0);
            // Assert
            mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
        }
        /// <summary>
        /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
        /// </summary>
        [TestMethod]
        public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
        {
            // Arrange 
            var stubEntityRepository = new Mock<IEntityRepository>();
            stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
                .Returns("Stub");
            const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub";
            var entity = new EntityClass(stubEntityRepository.Object);
            // Act 
            var name = entity.GetNameWithPrefix(12);
            // Assert
            Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name);
        }
    }
    public class EntityClass
    {
        private IEntityRepository _entityRepository;
        public EntityClass(IEntityRepository entityRepository)
        {
            this._entityRepository = entityRepository;
        }
        public string Name { get; set; }
        public string GetNameWithPrefix(int id)
        {
            string name = string.Empty;
            if (id > 0)
            {
                name = this._entityRepository.GetName(id);
            }
            return "Mr. " + name;
        }
    }
    public interface IEntityRepository
    {
        string GetName(int id);
    }
    public class EntityRepository:IEntityRepository
    {
        public string GetName(int id)
        {
            // Code to connect to DB and get name based on Id
            return "NameFromDb";
        }
    }
}

4

스텁 및 모의 테스트 관점 :

  • Stub정적 방식 즉, 구현 코드 작성 Stub에서 사용자에 의해 수행되는 더미 구현 입니다. 따라서 서비스 정의 및 동적 조건을 처리 할 수 ​​없습니다. 일반적으로 이는 모의 프레임 워크를 사용하지 않고 JUnit 프레임 워크에서 수행됩니다.

  • Mock 은 또한 더미 구현이지만 Mockito와 같은 Mocking 프레임 워크를 사용하여 구현이 역동적 으로 이루어 졌습니다. 따라서 조건과 서비스 정의를 동적 방식으로 처리 할 수 ​​있습니다. 즉, 런타임시 코드에서 모형을 동적으로 만들 수 있습니다. 따라서 mock을 사용하여 스텁을 동적으로 구현할 수 있습니다.


3

또한 유용한 답변, Subs보다 Mocks를 사용 하는 가장 강력한 포인트 중 하나

만약 주 코드가 의존하는 협력자 가 우리의 통제하에 있지 않다면 (예를 들어, 써드 파티 라이브러리에서),
이 경우, 스터브는 mock보다는 작성하기가 더 어렵습니다 .


2

차이점을 설명하기 위해 대답에 파이썬 예제를 사용했습니다.

Stub -Stubbing은 개발 수명주기 초기에 클래스의 메소드를 구현하는 데 사용되는 소프트웨어 개발 기술입니다. 이들은 일반적으로 알려진 인터페이스의 구현을위한 자리 표시 자로 사용되며, 여기서 인터페이스는 마무리되거나 알려져 있지만 구현은 아직 알려 지거나 마무리되지 않았습니다. 스텁으로 시작합니다. 이는 단순히 함수의 정의를 작성하고 나중에 실제 코드를 남겨둔다는 것을 의미합니다. 장점은 메서드를 잊어 버리지 않고 코드에서 디자인을 보면서 디자인에 대해 계속 생각할 수 있다는 것입니다. 스텁이 정적 응답을 리턴하여 응답을 코드의 다른 부분에서 즉시 사용할 수 있도록 할 수도 있습니다. 스텁 객체는 유효한 응답을 제공하지만 어떤 입력을 전달하더라도 정적이므로 항상 동일한 응답을받습니다.

class Foo(object):
    def bar1(self):
        pass

    def bar2(self):
        #or ...
        raise NotImplementedError

    def bar3(self):
        #or return dummy data
        return "Dummy Data"

모조품 객체는 모의 테스트 사례에서 사용되며 특정 메소드가 해당 객체에서 호출되는지 확인합니다. 모의 객체는 실제 객체의 동작을 제어 된 방식으로 모방하는 시뮬레이션 된 객체입니다. 일반적으로 다른 객체의 동작을 테스트하기 위해 모의 객체를 만듭니다. Mocks를 사용하면 단위 테스트에 사용할 수 없거나 다루기 어려운 리소스를 시뮬레이션 할 수 있습니다.

mymodule.py :

import os
import os.path

def rm(filename):
    if os.path.isfile(filename):
        os.remove(filename)

test.py :

from mymodule import rm
import mock
import unittest

class RmTestCase(unittest.TestCase):
    @mock.patch('mymodule.os')
    def test_rm(self, mock_os):
        rm("any path")
        # test that rm called os.remove with the right parameters
        mock_os.remove.assert_called_with("any path")

if __name__ == '__main__':
    unittest.main()

이것은 rm을 실행하고 호출 된 매개 변수를 주장하는 매우 기본적인 예입니다. 여기에 표시된 기능뿐만 아니라 객체와 함께 mock을 사용할 수 있으며 값을 반환하여 mock 객체를 사용하여 테스트 용 스텁을 교체 할 수 있습니다.

unittest.mock 에 대한 추가 정보 내용은 python 2.x mock의 참고 사항은 에 포함되어 있지 않지만 pip (pip install mock)를 통해 다운로드 할 수있는 다운로드 가능한 모듈입니다.

또한 Roy Osherove의 "The Unit of Art Testing"을 읽었으며 비슷한 책이 Python 및 Python 예제를 사용하여 작성되면 좋을 것 같습니다. 누구든지 그러한 책을 알고 있다면 공유하십시오. 건배 :)


2

스텁은 테스트 목적으로 만들어진 가짜 개체입니다. 모의는 예상 통화가 효과적으로 발생했는지 기록하는 스텁입니다.


2

스텁은 테스트 중에 처리되지 않은 예외를 피하기 위해 사용되는 빈 함수입니다.

function foo(){}

모의는 테스트 중에 OS, 환경 또는 하드웨어 종속성을 피하기 위해 사용되는 인공 기능입니다.

function foo(bar){ window = this; return window.toString(bar); }

주장과 상태 측면에서 :

  • 이벤트 또는 상태가 변경되기 전에 모크가 주장됩니다.
  • 스텁은 어설 션되지 않으며 관련없는 유닛에서 코드를 실행하지 않도록 이벤트 전에 상태를 제공합니다.
  • 스파이는 스텁과 같이 설정되고 이벤트 또는 상태 변경 후 주장됩니다.
  • 가짜는 주장되지 않으며 상태를 피하기 위해 하드 코딩 된 종속성이있는 이벤트 후에 실행됩니다.

참고 문헌


2
용어집에 스파이를 추가 할 때 +1 또한 "스파이는 스텁처럼 설정됩니다"가 아니라 "스파이는 모의처럼 설정됩니다"
Sameh Deabes


2

모의는 기술적이고 기능적인 대상입니다.

모의는 기술적 인 것 입니다. 바이트 코드 생성 덕분에 실제로 조롱 라이브러리 (EasyMock, JMockit 및 더 최근에는 Mockito가 알려져 있음)에 의해 생성 됩니다.
모의 구현은 우리가 계측 할 수있는 방식으로 생성 됩니다 메소드가 호출 될 때 특정 값을 반환하도록 할 되지만 모의 메소드가 특정 매개 변수 (엄격한 검사) 또는 어떤 매개 변수 ( 엄격한 검사 없음).

모의 인스턴스화 :

@Mock Foo fooMock

행동 기록 :

when(fooMock.hello()).thenReturn("hello you!");

호출 확인 :

verify(fooMock).hello()

Foo 클래스 / 동작을 인스턴스화 / 재정의하는 자연스러운 방법은 아닙니다. 이것이 제가 기술적 인 측면을 언급하는 이유입니다.

그러나 모의는 또한 SUT와 분리해야 할 클래스의 인스턴스이기 때문에 기능적 입니다. 그리고 그것에 기록 된 행동으로, 우리는 그루터기를 할 때와 같은 방식으로 SUT에서 사용할 수 있습니다.


그루터기는 단지 기능적인 객체 일뿐입니다 . 그것은 우리가 SUT와 분리해야하는 클래스의 인스턴스입니다. 즉, 단위 테스트 중에 필요한 스터브 클래스와 모든 동작 픽스처가 명시 적으로 정의되어야합니다.
예를 들어, 스텁 hello()하려면 Foo클래스 를 서브 클래 싱 하거나 인터페이스를 구현 해야합니다 hello() .

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

다른 테스트 시나리오에 다른 값 반환이 필요한 경우 반환을 설정하는 일반적인 방법을 정의해야합니다.

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

다른 시나리오 : 부작용 방법 (반환 없음)이 있고 해당 메소드가 호출되었는지 확인하려면 스텁 클래스에 부울 또는 카운터를 추가하여 메소드 호출 횟수를 계산해야합니다.


결론

스텁은 종종 단위 테스트를 위해 많은 오버 헤드 / 코드가 필요합니다. 즉시 레코딩 / 검증 기능을 제공하여 모의를 방지합니다.
그렇기 때문에 요즘 스텁 접근법은 훌륭한 모의 라이브러리의 출현과 함께 실제로 거의 사용되지 않습니다.


Martin Fowler 정보 기사 : 모의를 사용하는 동안 "모의가"프로그래머라고 생각하지 않으며 스텁을 피합니다.
그러나 필자는 실제로 필요할 때 모의를 사용하고 (성가신 종속성) 모의가 오버 헤드가되는 종속성이있는 클래스를 테스트 할 때 테스트 슬라이싱 및 미니 통합 테스트를 선호합니다.

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