java Mockito when().thenReturn()返回的值始终为空

qco9c6ql  于 2022-12-10  发布在  Java
关注(0)|答案(1)|浏览(377)

我有以下服务:

@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)而不是any(User.class),但结果是一样的。我在另一个项目中做了类似的测试,一切都很好。我不知道为什么在这种情况下不起作用。

lf5gs5x2

lf5gs5x21#

@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执行),并将mock示例分配给带注解的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));
    }

(This需要暂时使LimitService#coreService字段可访问)。示例输出:

@InjectMocks:
763677574
763677574
openMocks(this):
234857227
763677574

现在调用when为第二个mock示例设置存根,但是您的服务不知道这个示例,因为它只保存了对第一个mock示例的引用。
这个问题和相关问题在Why is my class not calling my mocked methods in unit test?的答案中讨论。

相关问题