Есть ли способ, используя Mockito, издеваться над одними методами в классе, но не над другими?
Например, в этом (по общему Stock
мнению, надуманном) классе я хочу смоделировать 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);
}
Ответы:
Чтобы прямо ответить на ваш вопрос, да, вы можете издеваться над одними методами, не насмехаясь над другими. Это называется частичной имитацией . См. Документацию Mockito по частичным макетам для получения дополнительной информации.
Для вашего примера вы можете сделать что-то вроде следующего в своем тесте:
В этом случае каждая реализация метода является ложной, если это не указано
thenCallRealMethod()
вwhen(..)
предложении.Существует также возможность шпионить, а не издеваться :
В этом случае все реализации метода являются реальными, кроме случаев, когда вы определили смоделированное поведение с помощью
when(..)
.Есть одна важная ловушка, когда вы используете
when(Object)
со шпионом, как в предыдущем примере. Будет вызван реальный метод (потому чтоstock.getPrice()
он оценивается раньшеwhen(..)
во время выполнения). Это может быть проблемой, если ваш метод содержит логику, которая не должна вызываться. Вы можете написать предыдущий пример так:Другой возможностью может быть использование
org.mockito.Mockito.CALLS_REAL_METHODS
, например:Это делегирует unstubbed вызовы для реальных реализаций.
Тем не менее, с вашим примером, я считаю , что это будет по- прежнему терпят неудачу, так как реализация
getValue()
зависит отquantity
иprice
, а неgetQuantity()
иgetPrice()
, что то , что вы насмехались.Другая возможность состоит в том, чтобы вообще избежать насмешек:
источник
Stock stock = spy(Stock.class);
Это кажется неправильным,spy
метод, кажется, принимает только объекты, а не классы.doReturn(retval).when(spyObj).methodName(args)
иwhen(spyObj.methodName(args)).thenReturn(retval)
Частичное издевательство над классом также поддерживается через шпион в mockito
Проверьте
1.10.19
и2.7.22
документы для подробного объяснения.источник
Согласно документам :
источник
class NaughtyLinkedList extends LinkedList { public int size() { throw new RuntimeException("don't call me");} } @Test public void partialMockNaughtLinkedList(){ List mock = mock(NaughtyLinkedList.class, CALLS_REAL_METHODS); mock.add(new Object()); // this calls the real function when(mock.size()).thenReturn(2); // For whatever reason, this lines throws the RuntimeException. assertEquals(2,mock.size()); }
Это не работает По какой-то причине, когда «когда» выполняется, он фактически выполняет метод, который должен быть смоделирован. Код:То, что вы хотите, в
org.mockito.Mockito.CALLS_REAL_METHODS
соответствии с документами:Таким образом, ваш код должен выглядеть так:
Призыв к
Stock stock = mock(Stock.class);
звонкам,org.mockito.Mockito.mock(Class<T>)
который выглядит так:Документы значения
RETURNS_DEFAULTS
говорят:источник
withSettings()...
? Похоже, чтоorg.mockito.internal.stubbing.answers.CallsRealMethods()
(например) может выполнить эту работу ... и Javadoc для этого класса специально говорит, что он предназначен для частичной насмешки ...thenReturn
будет ли фактически выполняться метод (который может вызвать проблемы, хотя и не в этом примере), и поэтомуdoReturn
предпочтительнее в таком случае ...?Частичная насмешка с использованием шпионского метода Mockito может стать решением вашей проблемы, как уже говорилось в ответах выше. В какой-то степени я согласен с тем, что для вашего конкретного случая использования было бы более уместно издеваться над поиском в БД. Исходя из моего опыта, это не всегда возможно - по крайней мере, без других обходных путей - которые я считаю очень громоздкими или, по крайней мере, хрупкими. Обратите внимание, что частичная имитация не работает с версиями Mockito для союзников. Вы используете по крайней мере 1.8.0.
Я бы просто написал простой комментарий к исходному вопросу вместо публикации этого ответа, но StackOverflow не позволяет этого.
Еще одна вещь: я действительно не могу понять, что часто здесь задают вопрос с комментарием «Почему вы хотите это сделать», по крайней мере, не пытаясь понять проблему. Особенно, когда дело доходит до необходимости частичной насмешки, есть много вариантов использования, которые я мог бы себе представить, где это было бы полезно. Вот почему ребята из Mockito предоставили такую функциональность. Эта функция, конечно, не должна быть чрезмерно использована. Но когда мы говорим о настройках тестового примера, которые иначе нельзя было бы установить очень сложным способом, следует использовать шпионаж.
источник