Mockito를 사용하여 일부 방법을 조롱하십시오.


402

Mockito를 사용하여 클래스의 일부 메소드를 조롱하는 방법이 있습니까?

예를 들어, (시피 고안)에서 Stock클래스 I는 모의 할 getPrice()getQuantity()(아래 시험 조각에 도시 된 바와 같이) 반환 값이지만 I는 원하는 getValue()부호화로 곱셈을 수행하는 Stock클래스

public class Stock {
  private final double price;
  private final int quantity;

  Stock(double price, int quantity) {
    this.price = price;
    this.quantity = quantity;
  }

  public double getPrice() {
    return price;
  }

  public int getQuantity() {
    return quantity;
  }
  public double getValue() {
    return getPrice() * getQuantity();
  }

  @Test
  public void getValueTest() {
    Stock stock = mock(Stock.class);
    when(stock.getPrice()).thenReturn(100.00);
    when(stock.getQuantity()).thenReturn(200);
    double value = stock.getValue();
    // Unfortunately the following assert fails, because the mock Stock getValue() method does not perform the Stock.getValue() calculation code.
    assertEquals("Stock value not correct", 100.00*200, value, .00001);
}

4
왜 그렇게 하시겠습니까? 클래스를 테스트하거나 (이 경우 전혀 조롱하지 않아야 함) 다른 클래스를 테스트하는 동안 (이 경우 기능이없는) 클래스를 조롱해야합니다. 왜 부분 모의를 하시겠습니까?
weltraumpirat

3
좋아, 이것은 실제의 작은 예입니다. 실제로, 나는 가치있는 값을 전달함으로써 데이터베이스에 대한 호출을 피하려고 노력하고 있지만 다른 방법이 그 가치있는 값과 올바르게 작동하는지 확인하고 싶습니다. 더 좋은 방법이 있습니까?
Victor Grazi 1

5
확실히 : 데이터베이스 호출을 별도의 클래스로 이동하십시오 (도메인 로직과 데이터베이스 액세스는 동일한 클래스에 있지 않아야합니다. 두 가지 다른 관심사입니다). 인터페이스를 추출하고 해당 인터페이스를 사용하여 도메인 로직 클래스에서 연결하고 테스트 중 인터페이스.
weltraumpirat

1
완전히 동의합니다. 제 3 자 라이브러리를 포함하여 여기에 코드 덩어리를 업로드하지 않고 전체 그림을 설명하는 것은 어렵습니다.
Victor Grazi 2013

1
당신은 아마 할 수 있습니다. 그러나 "더 나은 방법"은 아닙니다. 데이터베이스 코드는 응용 프로그램의 나머지 부분에서 숨기고 다른 패키지로 옮기려는 구현 세부 사항입니다. 후속 문장을 변경할 때마다 도메인 논리를 다시 컴파일하지 않아도됩니까?
weltraumpirat

답변:


643

질문에 직접 대답하기 위해 다른 방법을 조롱하지 않고 몇 가지 방법을 조롱 할 수 있습니다. 이것을 부분 모의 라고합니다 . 자세한 내용 은 부분 모의에 대한 Mockito 설명서 를 참조하십시오.

예를 들어 테스트에서 다음과 같은 작업을 수행 할 수 있습니다.

Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);    // Mock implementation
when(stock.getQuantity()).thenReturn(200);    // Mock implementation
when(stock.getValue()).thenCallRealMethod();  // Real implementation

이 경우 절 thenCallRealMethod()에서 지정하지 않으면 각 메소드 구현이 조롱 when(..)됩니다.

mock 대신 spy를 사용 하는 다른 방법도 있습니다 .

Stock stock = spy(Stock.class);
when(stock.getPrice()).thenReturn(100.00);    // Mock implementation
when(stock.getQuantity()).thenReturn(200);    // Mock implementation
// All other method call will use the real implementations

이 경우으로 조롱 된 동작을 정의한 경우를 제외하고 모든 메소드 구현이 실제 구현입니다 when(..).

when(Object)이전 예제에서와 같이 spy와 함께 사용할 때 중요한 함정이 있습니다 . 실제 메소드가 호출됩니다 ( 런타임 stock.getPrice()전에 평가되기 때문에 when(..)). 메소드에 호출해서는 안되는 논리가 포함되어 있으면 문제가 될 수 있습니다. 다음과 같이 이전 예제를 작성할 수 있습니다.

Stock stock = spy(Stock.class);
doReturn(100.00).when(stock).getPrice();    // Mock implementation
doReturn(200).when(stock).getQuantity();    // Mock implementation
// All other method call will use the real implementations

다음 org.mockito.Mockito.CALLS_REAL_METHODS과 같은 다른 가능성이 있습니다 .

Stock MOCK_STOCK = Mockito.mock( Stock.class, CALLS_REAL_METHODS );

이것은 스텁되지 않은 호출을 실제 구현에 위임합니다.


의 구현 때문에, 귀하의 예제와 함께, 나는 그것이 실패 할 것으로 예상 getValue()의존 quantity하고 price, 대신 getQuantity()getPrice()당신이 조롱 한 일이다.

또 다른 가능성은 모의를 피하는 것입니다.

@Test
public void getValueTest() {
    Stock stock = new Stock(100.00, 200);
    double value = stock.getValue();
    assertEquals("Stock value not correct", 100.00*200, value, .00001);
}

21
이 답변이 잘못되었다고 생각합니다. 클래스를 MOCK하지 않고 객체의 인스턴스를 감시해야합니다.
GaRRaPeTa

2
@GaRRaPeTa 저는 스파이와 조롱이 모두 합리적인 대안이라고 말합니다. OP는 이것이 간단한 예라고 명시하기 때문에이 경우에 가장 적합한 것을 말하기는 어렵습니다.
Jon Newmuis

1
"스파이"가 더 나은 방법으로 부분 모의 동굴을 제공하기 때문에 "모의"대신 "스파이"가 될 수 없습니다.
Tarun Sapra

2
Stock stock = spy(Stock.class);이것은 잘못된 것 같습니다. spy메소드는 클래스가 아닌 객체 만 허용하는 것 같습니다.
Paramvir Singh Karwal

4
+1 사이의 차이를 지적 doReturn(retval).when(spyObj).methodName(args)하고when(spyObj.methodName(args)).thenReturn(retval)
Captain_Obvious
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.