Java Mockito.When使用StringBuilder作为参数失败

时间:2017-01-31 14:03:14

标签: java mockito

以下是JUnit测试,oneLoginAuthUtil是Mocked。但Mockito.when正在返回null oneLoginAuthUtil.getMetaData 始终为null。以下是代码 -

public void func() throws Exception {
    StringBuilder b = new StringBuilder("test");
    RequestContext context = new RequestContext();
    Mockito.when(oneLoginAuthUtil.getMetaData(context, b)).thenReturn("abcdef");
    ResponseEntity<Object> response = loginControllerImpl.handleGetMetaDataEndPointImpl(context);
}

public String getMetaData(RequestContext context, StringBuilder b) throws Exception {
    Auth auth = getOneLoginAuthObject(context);
    final Saml2Settings settings = auth.getSettings();
    String metadata = settings.getSPMetadata();
    List<String> errors = Saml2Settings.validateMetadata(metadata);
    if (!errors.isEmpty()) {
        b.append(errors.toString());
        throw new SSOException("metadata_validation_error");
    }
    return metadata;
}

public ResponseEntity<Object> handleGetMetaDataEndPointImpl(RequestContext context) {
    try {
        StringBuilder b = new StringBuilder();
        String metadata = oneLoginAuthUtil.getMetaData(context, b);
        log.info(metadata);
        return new ResponseEntity<>(metadata, new HttpHeaders(), HttpStatus.CREATED);
    } catch (Exception e) {
        return new ResponseEntity<>("<error>Exception: " + e.getMessage() + "</error>", new HttpHeaders(),
                HttpStatus.CREATED);
    }
}

但没有oneLoginAuthUtil.getMetaData作为参数的StringBuilder方法可以正常工作。

2 个答案:

答案 0 :(得分:4)

返回null因为当您使用特定实例作为参数模拟方法时,当且仅当测试时提供的参数等于您在模拟时提供的参数时,Mockito将返回映射的返回值。显然不是这样的。 Mockito没有匹配,所以它返回一个方法的默认值,该方法返回一个名为null的模拟对象。

换句话说,Mockito.when(oneLoginAuthUtil.getMetaData(context, b))等同于Mockito.when(oneLoginAuthUtil.getMetaData(Mockito.eq(context), Mockito.eq(b))),此处类StringBuilder不会覆盖方法equals(Object obj),模拟时提供的实例不等于测试时提供的实例,因为它们不是同一个实例(依赖于equals(Object obj)的默认实现时唯一可能是相同的),这样就可以得到这种行为。

因此,您应该使用Mockito.any(StringBuilder.class)来匹配StringBuilder类型的任何实例,以便实例不再需要相等,那么您的代码将是:

Mockito.when(
    oneLoginAuthUtil.getMetaData(Mockito.eq(context), Mockito.any(StringBuilder.class))
).thenReturn("abcdef");

假设您的主要课程为LoginControllerImpl并且其成员字段oneLoginAuthUtil的类型为OneLoginAuthUtil,您可以使用注释@InjectMocks直接注入您的模拟键入OneLoginAuthUtil,完整的代码将是:

@RunWith(MockitoJUnitRunner.class)
public class LoginControllerImplTest {

    @Mock
    private OneLoginAuthUtil oneLoginAuthUtil;
    @InjectMocks
    private LoginControllerImpl loginControllerImpl;

    @Test
    public void func() throws Exception {
        RequestContext context = new RequestContext();
        Mockito.when(
            oneLoginAuthUtil.getMetaData(
                Mockito.eq(context), Mockito.any(StringBuilder.class)
            )
        ).thenReturn("abcdef");

        ResponseEntity<Object> response 
            = loginControllerImpl.handleGetMetaDataEndPointImpl(context);
        ...
    }
}

答案 1 :(得分:3)

StringBuilder未实现equals()hashCode(),因此无法像这样使用参数匹配。

问题实际上是你不应该将一个可变对象(例如StringBuilder)传递给你的测试对象。为什么返回&#34;元数据&#34;要求您附加到范围之外的StringBuilder吗?