Насмешка предиката в Java с использованием Mockito - PullRequest
0 голосов
/ 06 апреля 2020

У меня есть предикат, который проверяет наличие строки в базе данных. Я не уверен, что это хорошее использование предиката, но он сделал мой код чистым и лаконичным. Но когда я тестирую этот код, я не могу подделать класс DAO и не уверен, почему это так.

public class validator{

public Predicate<String> doesRowExists = fileName -> makeDao().isRowReturned(RowId);

  public AlertFileDAO makeDataDao(){
        return new DataDao();
    }

  public boolean validate(String RowId){
        return doesRowExists.test(rowId)
    }

}

//Test

public class ValidatorTest{

@setup
void beforeAll(){
  mockValidator = spy(new Validator());
  doReturn(mockDataDao)
                .when(mockValidator)
                .makeDataDao();
}

@Test
test_whenRowExists(){
new Validator.validate("1-abc-34");
}

Когда я запускаю тест, он попадает в реальную базу данных и не использует фиктивный класс DAO. Я не уверен, чего именно мне здесь не хватает. предложить.

Ответы [ 2 ]

2 голосов
/ 09 апреля 2020

Почему бы вам просто не встроить предикат и не передать дао в качестве аргумента конструктора? Это делает ваш 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));
    }

}
1 голос
/ 06 апреля 2020

Я вижу вашу проблему как пример более распространенной задачи: как заглушить поле . В вашем случае вам нужно заглушить поле doesRowExists.

Общая задача имеет общее решение: вместо нее использовать getter : public Predicate<String> getDoesRowExists() { return doesRowExists;} или, с общим стилем кода, public Predicate<String> isRowExists() { return doesRowExists;}

Итак, в вашем рабочем коде вы вызываете getter вместо поля: return isRowExists().test(rowId)
В своем тестовом коде вы просто издеваетесь над этим геттером: when(isRowExists).thenReturn(true)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...