java - Spring Boot 服务层单元测试中模拟原始字符串

标签 java spring junit mockito

我正在尝试为按名称查找玩家的服务层方法编写单元测试。该方法调用 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);
}

最佳答案

我花了一段时间才弄清楚这个问题。

thenReturn中,您正在调用any(Page.class)。相反,您应该返回实际的 Page 对象或模拟 Page 对象。

最好避免使用“any”,除非您无法知道其身份。

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 中方法的参数并验证。它们不应该传递给测试对象,也不应该从任何模拟对象返回。

关于java - Spring Boot 服务层单元测试中模拟原始字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60306567/

相关文章:

java - java中JSON字符串到String数组

java - 如何使用 RxJava2 将不同的异步源聚合为一个?

java - 从 Spring Controller 加载 CSS

java - 使用 ejb ql 从数据库中选择随机行

java - 将对象传递到工厂

java - 使用 snakeyaml(导入 junit 库)将 .yml 文件加载到 HashMap 中

java - JUnit @Rule 生命周期与@Before 交互

无法调用 Spring Boot @Controller,但 @RestController 有效

java - 双向 Web 服务通信 REST

java - JUnit 引用相同的 var 值