我有以下服务:
@Service
@RequiredArgsConstructor
public class LimitService {
private final CoreService coreService;
private final AuditService audit;
public Limit get(User user) {
Limit limit = coreService.get(user);
if (limit != null) {
Optional.ofNullable(limit.getAvailable())
.map(String::valueOf)
.map(BigDecimal::new)
.map(availableValue -> availableValue.setScale(2, RoundingMode.HALF_DOWN))
.map(BigDecimal::doubleValue)
.ifPresentOrElse(val -> limit.setAvailable(val), () -> limit.setAvailable(0d));
}
return limit;
}
}
和以下相关测试
@ExtendWith(MockitoExtension.class)
public class LimitServiceTest {
@Mock
private CoreService coreService;
@Mock
private AuditService audit;
@InjectMocks
private LimitService service;
@BeforeEach
public void init(){
MockitoAnnotations.openMocks(this);
}
@Test
public void shouldReturnNull(){
assertThat(this.service.get(new User())).isNull();
}
@Test
public void shouldSetToZero_whenNull(){
User user = new User();
Mockito.when(this.coreService.get(any(User.class)))
.thenReturn(new Limit());
assertThat(this.service.get(user)).extracting(Limit::getAvailable)
.isEqualTo(0d);
}
}
当我在调试模式下运行第二个测试时,我可以看到实际上为CoreService生成了一个mock,但Mockito似乎忽略了When ..thenReturn.
我也尝试使用eq(user)而不是任何(user .class),但结果是一样的。我在另一个项目中进行了类似的测试,一切都很好。我不知道为什么在这种情况下不工作。
@ExtendWith(MockitoExtension.class)
public class LimitServiceTest {
@Mock
private CoreService coreService;
@Mock
private AuditService audit;
@InjectMocks
private LimitService service;
@BeforeEach
public void init(){
MockitoAnnotations.openMocks(this);
}
// ...
@InjectMocks
首先运行(由MockitoExtension
执行),并将模拟实例分配给带注释的LimitService
字段中的字段。
稍后,openMocks
创建第二组模拟实例,并将它们分配给测试中的字段(但不重新分配服务的字段)。服务仍然会引用由扩展创建的模拟实例。
这可以通过在调用openMocks
之前和之后打印字段的身份哈希码来验证:
@BeforeEach
public void init(){
System.err.println("@InjectMocks:");
System.err.println(System.identityHashCode(coreService));
System.err.println(System.identityHashCode(service.coreService));
MockitoAnnotations.openMocks(this);
System.err.println("openMocks(this):");
System.err.println(System.identityHashCode(coreService));
System.err.println(System.identityHashCode(service.coreService));
}
(这需要暂时使LimitService#coreService
字段可访问)。示例输出:
@InjectMocks:
763677574
763677574
openMocks(this):
234857227
763677574
调用when
现在为第二个模拟实例设置存根,但是您的服务不知道这个实例,因为它只保存对第一个模拟实例的引用。
这个和相关的问题在"为什么我的类在单元测试中不调用我的模拟方法"的回答中讨论。