java mockito教學 - 使用Mockito嘲笑一些方法,但不是其他方法




mockito教程 mockito中文 (5)

部分嘲笑類也支持通過間諜在mockito

List list = new LinkedList();
List spy = spy(list);

//optionally, you can stub out some methods:
when(spy.size()).thenReturn(100);

//using the spy calls real methods
spy.add("one");
spy.add("two");

//size() method was stubbed - 100 is printed
System.out.println(spy.size());

詳細解釋請查看1.10.192.7.22文檔。

有沒有什麼方法可以用Mockito來嘲笑課堂上的某些方法,而不是其他方法?

例如,在這個(可以承擔的)股票類中,我想模擬getPrice()和getQuantity()返回值(如下面的測試代碼片段所示),但是我想讓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);
}

根據docs

Foo mock = mock(Foo.class, CALLS_REAL_METHODS);

// this calls the real implementation of Foo.getSomething()
value = mock.getSomething();

when(mock.getSomething()).thenReturn(fakeValue);

// now fakeValue is returned
value = mock.getSomething();

使用Mockito的間諜方法進行部分嘲弄可能是解決您的問題的方法,正如上面的答案中所述。 在某種程度上,我同意,對於具體的用例,嘲笑數據庫查找可能更合適。 根據我的經驗,這並不總是可行的 - 至少不是沒有其他解決方法 - 我認為這是非常麻煩或至少是脆弱的。 請注意,部分嘲諷不適用於盟友版本的Mockito。 您至少使用1.8.0。

我只是寫了一個簡單的原始問題的評論,而不是發布這個答案,但不允許這樣做。

還有一件事:我真的無法理解,在這裡問一個問題的次數很多時會在“你為什麼要這麼做”的問題上得到評論,而沒有至少試圖理解問題。 特別是當涉及到需要部分模擬的時候,真的有很多用例可以想像它會在哪裡有用。 這就是Mockito提供這種功能的原因。 這個功能當然不會被過度使用。 但是當我們談論測試用例設置,否則無法以非常複雜的方式建立時,應該使用間諜。


根據問題接受的答案是不正確的。

Stock stock = mock(Stock.class);的呼叫Stock stock = mock(Stock.class); 調用org.mockito.Mockito.mock(Class<T>) ,如下所示:

 public static <T> T mock(Class<T> classToMock) {
    return mock(classToMock, withSettings().defaultAnswer(RETURNS_DEFAULTS));
}

值為RETURNS_DEFAULTS的文檔告訴:

/**
 * The default <code>Answer</code> of every mock <b>if</b> the mock was not stubbed.
 * Typically it just returns some empty value. 
 * <p>
 * {@link Answer} can be used to define the return values of unstubbed invocations. 
 * <p>
 * This implementation first tries the global configuration. 
 * If there is no global configuration then it uses {@link ReturnsEmptyValues} (returns zeros, empty collections, nulls, etc.)
 */

根據文檔,你想要的是org.mockito.Mockito.CALLS_REAL_METHODS

/**
 * Optional <code>Answer</code> to be used with {@link Mockito#mock(Class, Answer)}
 * <p>
 * {@link Answer} can be used to define the return values of unstubbed invocations.
 * <p>
 * This implementation can be helpful when working with legacy code.
 * When this implementation is used, unstubbed methods will delegate to the real implementation.
 * This is a way to create a partial mock object that calls real methods by default.
 * <p>
 * As usual you are going to read <b>the partial mock warning</b>:
 * Object oriented programming is more less tackling complexity by dividing the complexity into separate, specific, SRPy objects.
 * How does partial mock fit into this paradigm? Well, it just doesn't... 
 * Partial mock usually means that the complexity has been moved to a different method on the same object.
 * In most cases, this is not the way you want to design your application.
 * <p>
 * However, there are rare cases when partial mocks come handy: 
 * dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.)
 * However, I wouldn't use partial mocks for new, test-driven & well-designed code.
 * <p>
 * Example:
 * <pre class="code"><code class="java">
 * Foo mock = mock(Foo.class, CALLS_REAL_METHODS);
 *
 * // this calls the real implementation of Foo.getSomething()
 * value = mock.getSomething();
 *
 * when(mock.getSomething()).thenReturn(fakeValue);
 *
 * // now fakeValue is returned
 * value = mock.getSomething();
 * </code></pre>
 */

因此你的代碼應該如下所示:

import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

public class StockTest {

    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, withSettings().defaultAnswer(CALLS_REAL_METHODS));
        when(stock.getPrice()).thenReturn(100.00);
        when(stock.getQuantity()).thenReturn(200);
        double value = stock.getValue();

        assertEquals("Stock value not correct", 100.00 * 200, value, .00001);
    }
}

括號放置不當。 你必須使用

doThrow(new Exception()).when(mockedObject).methodReturningVoid(...);
                                          ^

並不是

doThrow(new Exception()).when(mockedObject.methodReturningVoid(...));
                                                                   ^

這在文檔中有解釋





java mocking mockito