java - 在 Spring Boot 服务层的单元测试中模拟原始字符串
问题描述
我正在尝试为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);
}
解决方案
我花了一段时间才弄清楚这一点。
在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
参数verify
。它们不应该传递给测试对象,也不应该从任何模拟对象返回。
推荐阅读
- json - 来自 Parquet 文件的 Redshift COPY 将 JSON 列解释为多列
- google-bigquery - 如何将数组中元素的出现计数为 SQL 表中的新列?
- c++ - Xcode 找不到 PortAudio 的标签“错误”
- java - 我对某些数组整数的删除方法有什么问题?
- java - 如何更改输入文件中的所有字母并在输出文件中将它们打印为大写?
- linux - 如何找到文件的总大小(以字节为单位)?
- php - 结合 SQL 结果的最佳方法?2 个请求对 1 个?
- reactjs - 用玩笑测试隐藏字段的存在/不存在
- javascript - 在 Chart.js 中扩展数据系列的问题
- javascript - django_tables2 & excelTableFilter 覆盖标题 chevron