Почему бы вам просто не встроить предикат и не передать дао в качестве аргумента конструктора? Это делает ваш API чище: вызов метода против getter для предиката и тестирование предиката, с которым вы в конечном итоге столкнулись.
С вашим принятым ответом пользователь должен использовать следующее:
validator.doesRowExist().test(rowId);
Я считаю, что было бы проще использовать следующее:
validator.doesRowExist(rowId);
или даже:
validator.validate(rowId);
Давайте сделаем серию рефакторингов для достижения этого:
Шаг 1:
Вы используете свой предикат для реализации функции validate
, Других вызовов и передачи другим функциям нет (функции высшего порядка, принимающие предикат, типичны для них). Давайте изменим предикат на метод:
public class Validator {
public DataDao makeDataDao(){
return new DataDao();
}
public boolean validate(String rowId){
return doesRowExist(rowId);
}
private boolean doesRowExist(String rowId) {
return makeDataDao().isRowReturned(rowId);
}
}
Шаг 2:
Daos обычно являются одиночными (достаточно одного экземпляра). В зависимости от используемой вами структуры создание Dao может быть более дорогостоящим, чем вызов метода для него. Давайте применим принципы внедрения зависимостей (класс получает зависимости, а не создает их):
public class Validator {
private final DataDao dataDao;
Validator(DataDao dataDao) {
this.dataDao = dataDao;
}
public boolean validate(String rowId){
return doesRowExist(rowId);
}
private boolean doesRowExist(String rowId) {
return dataDao.isRowReturned(rowId);
}
}
Если вам действительно нужно каждый раз создавать Dao, вы можете предоставить fecory в конструкторе.
Результат:
Ваш класс:
- имеет более приятный API
- , вероятно, более эффективен
- легко проверяется:
@ExtendWith(MockitoExtension.class)
public class ValidatorTest {
@Mock
DataDao mockDataDao;
@InjectMocks
Validator validator;
@Test
void whenValidateReturnsValueFromIsRowReturned(){
var rowId = "1-abc-34";
doReturn(false)
.when(mockDataDao)
.isRowReturned(rowId);
assertEquals(false, validator.validate(rowId));
}
}