Задать вопрос
DennisKingsman
@DennisKingsman
Студент

Почему Mock выдает некорректные данные?

Здравствуйте, у меня есть тест класс
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest
public class UserRepositoryImplTest {

    private static final Logger log = LoggerFactory.getLogger(UserRepositoryImplTest.class);

    @Mock
    JdbcTemplate jdbcTemplate;

    @Before
    public void initMocks(){
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void findByNameTest() {
        User user = setupUser();
        String userName = user.getUserName();
        UserRepository userRepository = new UserRepositoryImpl();
        ReflectionTestUtils.setField(userRepository, "jdbcTemplate", jdbcTemplate);
        Mockito.when(jdbcTemplate.queryForObject(
                FIND_BY_NAME,
                new ForUnitTestUserRowMapper(),
                userName))
                .thenReturn(user);
        assertEquals(user, userRepository.findByName(userName));
    }

}

Я делал его по следующему примеру: Пример.
Но я получаю NPE при попытке сравнить то что возвращает мок и подготовленный результат.
Вот стектрейс ошибки и логи до нее
16:23:10.048 [main] DEBUG org.springframework.test.util.ReflectionTestUtils - Setting field 'jdbcTemplate' of type [null] on target object [com.trainig.spring.main.project.repository.user.UserRepositoryImpl@7d61eccf] or target class [class com.trainig.spring.main.project.repository.user.UserRepositoryImpl] to value [jdbcTemplate]
16:23:10.101 [main] INFO com.trainig.spring.main.project.repository.user.UserRepositoryImpl - find by name : name
16:23:10.121 [main] INFO com.trainig.spring.main.project.repository.user.UserRepositoryImpl - Empty user

java.lang.NullPointerException
at com.trainig.spring.main.project.entity.User.equals(User.java:136)
com.training.spring.main.project.repository.user.UserRepositoryImplTest.findByNameTest(UserRepositoryImplTest.java:50)
...
[MockitoHint] UserRepositoryImplTest.findByNameTest (see javadoc for MockitoHint):
[MockitoHint] 1. Unused... -> at com.training.spring.main.project.repository.user.UserRepositoryImplTest.findByNameTest(UserRepositoryImplTest.java:45)
[MockitoHint] ...args ok? -> at com.trainig.spring.main.project.repository.user.UserRepositoryImpl.findByName(UserRepositoryImpl.java:63)


вот метод для подготовки объекта для тестирования:
public static User setupUser() {
        User user = new User();
        user.setUserId(ID);
        user.setUserName(USER_NAME);
        user.setUserPassword(PASSWORD);
        user.setRoles(Collections.singleton(new Role(ID, USER_ROLE)));
        return user;
    }


вот метод который я тестирую :
@Override
    public User findByName(String userName) {
        logger.info("find by name : {}", userName);
        User user = jdbcTemplate.queryForObject(
                FIND_BY_NAME,
                (rs, rowNum) -> new User(
                        rs.getLong("user_id"),
                        rs.getString("user_name"),
                        rs.getString("user_password"),
                        Collections.singleton(new Role(
                                rs.getLong("role_id"),
                                rs.getString("role_name")
                        ))),
                userName);
        if (Objects.isNull(user)) {
            logger.info("Empty user");
            return new User();
        } else {
            return user;
        }
    }

Вот запрос который я использую
public static final String FIND_BY_NAME = "select ut.user_id, ut.user_name, ut.user_password," +
            " user_role.role_id, role_name from \n" +
            "user_role inner join user_to_role\n" +
            "on user_role.role_id = user_to_role.role_id \n" +
            "inner join user_table as ut\n" +
            "on ut.user_id = user_to_role.user_id\n" +
            "where ut.user_name = ?";


Тестовый метод работает если в репозитории в моменте проверки на ноль, вернуть не нового юзера, а засетапленного юзера. Из чего я делаю вывод, что результатом работы мока становится результат работы самого метода, а не то что я написал в
.thenReturn(user)

Тоесть если в классе UserRepositoryImpl
поменять с
if (Objects.isNull(user)) {
            logger.info("Empty user");
            return new User();
        } else {
            return user;
        }


на
if (Objects.isNull(user)) {
            logger.info("Empty user");
            return ModelUtil.setupUser();
        } else {
            return user;
        }

то тест отрабатывает корректно. Что я должен делать чтобы корректно работал
Mockito.when(jdbcTemplate.queryForObject(
                FIND_BY_NAME,
                new ForUnitTestUserRowMapper(),
                userName))
               <b> .thenReturn(user);</b>

?
  • Вопрос задан
  • 263 просмотра
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 1
xez
@xez Куратор тега Java
TL Junior Roo
1. Cамое главное. Нет никакого смысла в интеграциионых тестах мокать базу данных. Для этого используйте лучше testcontainers (на худой конец h2, но это верный способ выстрелить себе в ногу).
2.
ReflectionTestUtils.setField(userRepository, "jdbcTemplate", jdbcTemplate);
wtf? Неужели нет другого способа?
3. Для мока следует использовать "матчеры" eq, any и т.д.
Попробуйте что-то типа такого:
Mockito.when(jdbcTemplate.queryForObject(
                eq(FIND_BY_NAME),
                any(ForUnitTestUserRowMapper.class),
                anyString())
               .thenReturn(user);
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы