Частичное издевательство считается плохой практикой? (Mockito)
Я тестирую бизнес-объект с использованием Mockito. Бизнес-объект использует DAO, который обычно получает данные из БД. Чтобы протестировать бизнес-объект, я понял, что проще использовать отдельный DAO в памяти (который хранит данные в HashMap), чем писать все
when(...).thenReturn(...)
заявления. Чтобы создать такой DAO, я начал с частичной насмешки над моим интерфейсом DAO следующим образом:
when(daoMock.getById(anyInt())).then(new Answer() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
int id = (Integer) invocation.getArguments()[0];
return map.get(id);
}
});
но мне пришло в голову, что было проще просто реализовать саму новую реализацию DAO (используя HashMap в памяти), даже не используя Mockito (не нужно получать аргументы из этого объекта InvocationOnMock) и заставить протестированный бизнес-объект использовать этот новый DAO.
Кроме того, я читал, что частичная насмешка считалась плохой практикой. Мой вопрос: что я делаю плохую практику в моем случае? Каковы недостатки? Мне это кажется нормальным, и мне интересно, какие могут быть потенциальные проблемы.
2 ответа
Мне интересно, зачем вам нужен ваш поддельный DAO, чтобы HashMap
, Мне интересно, не слишком ли сложны ваши тесты. Я большой поклонник очень простых методов тестирования, каждый из которых проверяет один аспект поведения вашего SUT. В принципе, это "одно утверждение на тест", хотя иногда я получаю небольшую горстку фактического assert
или же verify
линии, например, если я утверждаю правильность сложного объекта. Пожалуйста, прочитайте http://blog.astrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/ или http://blog.jayfields.com/2007/06/testing-one-assertion-per-test.html чтобы узнать больше об этом принципе.
Таким образом, для каждого метода тестирования вы не должны использовать ваш поддельный DAO снова и снова. Скорее всего, один раз или два, самое большее. Поэтому, имея большой HashMap
мне кажется, что полные данные ЛЮБЫЕ избыточны, ИЛИ признаком того, что ваш тест ДЕЙСТВИТЕЛЬНО работает лучше, чем должен. Для каждого метода тестирования вам действительно нужен только один или два элемента данных. Если вы настроите их, используя Mockito для вашего интерфейса DAO, и when ... thenReturn
в самом методе теста каждый тест будет простым и читаемым, потому что данные, которые использует конкретный тест, будут сразу же видны.
Вы также можете ознакомиться с шаблоном "упорядочить, действовать, заявить" ( http://www.arrangeactassert.com/why-and-what-is-arrange-act-assert/ и http://www.telerik.com/help/justmock/basic-usage-arrange-act-assert.html) и будьте осторожны при реализации этого шаблона ВНУТРИ каждого метода тестирования, а не разбрасывайте его различные части по всему классу тестирования.
Не видя больше вашего реального тестового кода, трудно понять, какие еще советы вам дать. Предполагается, что Mockito делает насмешку легче, а не сильнее; так что если у вас есть тест, где это не происходит для вас, то, безусловно, стоит спросить, делаете ли вы что-то нестандартное. То, что вы делаете, не является "частичной насмешкой", но это, безусловно, кажется мне чем-то вроде испытательного запаха. Не в последнюю очередь потому, что он объединяет множество ваших методов тестирования - спросите себя, что произойдет, если вам придется изменить некоторые данные в HashMap
,
Вы также можете найти https://softwareengineering.stackexchange.com/questions/158397/do-large-test-methods-indicate-a-code-smell полезным.
При тестировании своих уроков я часто использую комбинацию макетов, сделанных мокито, а также подделок, которые вы очень описываете. В вашей ситуации я согласен, что поддельная реализация звучит лучше.
Нет ничего особенно плохого в частичных имитациях, но становится немного сложнее определить, когда вы вызываете реальный объект и когда вы вызываете ваш смоделированный метод - особенно потому, что Mockito молча не может смоделировать финальные методы. Невинно выглядящие изменения в исходном классе могут изменить реализацию частичного макета, в результате чего ваш тест перестанет работать.
Если у вас есть гибкость, я рекомендую извлечь интерфейс, который предоставляет метод, который вам нужно вызвать, что облегчит выбор макета или подделки.
Чтобы написать подделку, реализуйте этот маленький интерфейс без Mockito, используя простой класс (вложенный в ваш тест, если хотите). Это позволит очень легко увидеть, что происходит; Недостатком является то, что если вы пишете очень сложный подделку, вы можете обнаружить, что вам тоже нужно проверить подделку. Если у вас есть много тестов, которые могут использовать хорошую реализацию Fake, это может стоить дополнительного кода.
Я настоятельно рекомендую статью Мартина Фаулера "Не издевайся", известную своей книгой " Рефакторинг". Он перебирает названия разных типов тестовых двойников и различия между ними.