Перемешивание необработанной строки в модульном тестировании для сервисного уровня Spring Boot - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь написать модульные тесты для метода уровня обслуживания, находящего Player s по имени. Метод вызывает метод репозитория JPA и возвращает объект Page. Я хочу, чтобы тест подтвердил, что правильный метод из репозитория действительно был вызван.

Класс теста

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {PlayerService.class})
public class PlayerServiceTest {

    @Autowired
    PlayerService playerService;

    @MockBean
    PlayerRepository playerRepository;


    @Test
    public void whenListPlayersByName_thenShouldCallFindMethodWithPageableArgAndNameArg(){
        Pageable pageableStub = Mockito.mock(Pageable.class);
        String name = "xxx";
        Mockito.when(playerRepository.findByNameContainingIgnoreCase(any(String.class), any(Pageable.class)))
                .thenReturn(any(Page.class));

        //1st attempt:
        //playerService.listPlayersByName(name, pageableStub);
        playerService.listPlayersByName(eq(name), pageableStub);

        verify(playerRepository).findByNameContainingIgnoreCase(any(String.class), any(Pageable.class));
    }

Моя проблема

Тест не пройден с сообщением:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.domin0x.player.PlayerServiceTest.whenListPlayersByName_thenShouldCallFindMethodWithPageableArgAndNameArg(PlayerServiceTest.java:60)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

Следуя совету, я изменил name на eq(name), но это приводит к другой проблеме:

Argument(s) are different! Wanted:
com.domin0x.player.PlayerRepository#0 bean.findByNameContainingIgnoreCase(
    <any java.lang.String>, <any org.springframework.data.domain.Pageable>);

Actual invocation has different arguments:
com.domin0x.player.PlayerRepository#0 bean.findByNameContainingIgnoreCase(
null,     Mock for Pageable, hashCode: 309271464
;

Любой совет, что я должен изменить в тесте?

Класс обслуживания

@Service
public class PlayerService {
    public Page<Player> listPlayersByName(String name, Pageable pageable) {
        return repository.findByNameContainingIgnoreCase(name, pageable);
    }

Интерфейс хранилища

@Repository
public interface PlayerRepository extends JpaRepository<Player, Integer> {

    Page<Player> findByNameContainingIgnoreCase(String name, Pageable pageable);
}

1 Ответ

2 голосов
/ 19 февраля 2020

Мне понадобилось время, чтобы понять это.

в thenReturn, вы звоните any(Page.class). Вместо этого вы должны вернуть либо фактический Page объект, либо фиктивный Page объект).

Также лучше избегать использования «любого», если у вас нет возможности узнать личность.

Page<Player> pageStub = (Page<Player>)Mockito.mock(Page.class);
Mockito.when(playerRepository.findByNameContainingIgnoreCase(name, pageableStub))
            .thenReturn(pageStub);

Page<PlayerStub> result = playerService.listPlayersByName(name, pageableStub);

assertSame(pageStub, result);

// No need to call verify, since it couldn't get pageStub without calling the correctly stubbed method.

Для пояснения: eq(), any() и другие "сопоставители" должны использоваться только в качестве аргументов для методов в when и verify. Они никогда не должны передаваться испытуемому или возвращаться с какого-либо предмета.

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