Комментарии 4
Спасибо автору за статью. Вот работаешь 5 лет, используешь мокито, а как работает не знаешь… и тут статья такая, что даёт время подумать.
Mockito и подобные фреймворки используют динамическую генерацию классов, а не проксирование. Этот org.own.ArticleExample1$Apple$MockitoMock$692964397
— сгенерированный наследник класса ArticleExample1.Apple. Поэтому если вы его объявите как final, то все упадет.
Proxy может делать динамические классы только для интерфейсов, что сильно ограничивает его использование.
Apple.class.getInterfaces(), (proxy, method, args1) -> {
System.out.println("Called getColor() method on Apple");
return method.invoke(new Apple(), args1);
});
В этом хэндлере есть нетривиальная ошибка, связанная с исключениями, про которую всегда все забывают. Вызов method.invoke() в случае исключения обернет его в InvocationTargetException, на который может не сработать хендлер в вызывающем коде. Правильно будет так:
Apple.class.getInterfaces(), (proxy, method, args1) -> {
System.out.println("Called getColor() method on Apple");
try {
return method.invoke(new Apple(), args1);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
});
Никогда не понимал, зачем нужны эти mock фреймворки. Если нужен класс для тестирования то можно просто его сделать
private static class MockApple extends Apple {
public String getName() {return "Red";}
}
@Test
public void basic() {
Apple apple = new MockApple();
assertEquals("Red", apple.getName()); // true
}
Намного проще чем учить все нюансы работы mock фреймворка, все эти when и thenReturn. Работает точно также.
В чем смысл и какая польза от этих mock фреймворков.
Возможно, это моя ошибка. Я посчитал, что плюсы использования mock-фреймворка очевидны и не стал писать его как часть статьи, хотя вскользь его применимость все же упомянул.
В вашем приведенном примере действительно можно обойтись без mock-фреймворка (хотя там даже тестировать нечего). И во многих других случаях также можно обойтись без них. Но также в очень многих приложениях нужно "мокнуть" какой-то большой класс, у которого есть не только метод getName, а множество других. Если использовать ваш подход то придется для каждого из них писать имплементацию метода. А теперь добавьте к этому то, что тестируемый класс может менять свою структуру (добавятся новые методы, какие-то удалятся и тд). В каждом их этих изменений вам придется менять свой MockApple.
Также эти "нюансы" работы mock-фреймворков (и речь не только про when-thenReturn) позволяют вам, например, возвращать какое-то конкретное значение в зависимости от входных данных прямо в самом юнит-тесте. Например, вы можете генерировать различные входные данные и проверять их выход (хотя с точки зрения тестирования это может быть не совсем верный подход)
Таким образом, использовать mockito и подобные фреймворки во всех тестах, разумеется, необязательно. Но обычно плюсы, которые дает этот фреймворк перевешивают его стоимость использования
Mockito. Из чего он приготовлен и как его подавать?