如何从 Mockito Junit 正确调用 super class 方法

How to call super class method correctly from Mockito Junit

我有一个基本处理程序

public class BaseHandler {
    protected Object extractInput(RoutingContext rc) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.put("baseKey", "baseValue");
        return jsonObject
    }
}

还有一个子处理程序

public class ChildHandler extends BaseHandler {

    @Override
    protected Object extractInput(RoutingContext rc) {
        JsonObject jsonObject = (JsonObject) super.extractInput(rc);
        populateFileObjects(rc).ifPresent(jsonArray -> json.put("fileUploads", jsonArray));
        return jsonObject
    }
}

我已经使用 Mockito 编写了 Junit 代码

@Test
public void extractInputTest() {
    ChildHandler handler = spy(new ChildHandler());
    RoutingContext rc = mock(RoutingContext.class);

    JsonObject jsonObject = new JsonObject();
    jsonObject.put("key", "value");

    JsonArray jsonArray = new JsonArray();
    JsonObject fileObject = new JsonObject();
    fileObject.put("fileName", "name");
    jsonArray.add(fileObject);
    Optional<JsonArray> optional = Optional.of(jsonArray);

    doReturn(jsonObject).when((BaseHandler)handler).extractInput(eq(rc));
    doReturn(optional).when(handler).populateFileObjects(rc);

    Object o = handler.extractInput(rc);
    Map<String, Object> map = ((JsonObject) o).getMap();

    Assert.assertEquals("value", ((JsonObject)o).getString("key"));
    Assert.assertEquals(2, map.size()); //Junit fails here
    Assert.assertEquals(JsonArray.class, map.get("fileUploads").getClass());
    Assert.assertEquals(fileObject, ((JsonArray)map.get("fileUploads")).getJsonObject(0));
} 

我尝试将断点放在 ChildHandler class 的 extractInput 方法的第一行,但发现它从未被调用过。

模拟 super.method 调用的正确方法是什么?

有一种方法可以做到这一点,但它不是很干净,但它比用 Java 反射做同样肮脏的事情要好。您应该在子 class 的另一个方法中提取对 super 方法的调用,例如:

public class ChildHandler extends BaseHandler {

    @Override
    protected Object extractInput(RoutingContext rc) {
        JsonObject jsonObject = (JsonObject) superExtractInput(rc);
        populateFileObjects(rc).ifPresent(jsonArray -> json.put("fileUploads", jsonArray));
        return jsonObject
    }

    protected Object superExtractInput(RoutingContext rc){
        super.extractInput(rc);
    }
}

你的测试看起来像:

@Test
public void extractInputTest() {
    ChildHandler handler = spy(new ChildHandler());
    RoutingContext rc = mock(RoutingContext.class);

    JsonObject jsonObject = new JsonObject();
    jsonObject.put("key", "value");

    JsonArray jsonArray = new JsonArray();
    JsonObject fileObject = new JsonObject();
    fileObject.put("fileName", "name");
    jsonArray.add(fileObject);
    Optional<JsonArray> optional = Optional.of(jsonArray);

    doReturn(jsonObject).when(handler).superExtractInput(eq(rc));
    doReturn(optional).when(handler).populateFileObjects(rc);

    Object o = handler.extractInput(rc);
    Map<String, Object> map = ((JsonObject) o).getMap();

    Assert.assertEquals("value", ((JsonObject)o).getString("key"));
    Assert.assertEquals(2, map.size()); //Junit fails here
    Assert.assertEquals(JsonArray.class, map.get("fileUploads").getClass());
    Assert.assertEquals(fileObject, ((JsonArray)map.get("fileUploads")).getJsonObject(0));
} 

最好favor composition over inheritance,避免在测试阶段出现此类问题。

classes 就像:

public class BaseHandler {
    protected Object extractInput(RoutingContext rc) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.put("baseKey", "baseValue");
        return jsonObject
    }
}

public class ChildHandler{

    private final BaseHandler baseHandler;

    public ChildHandler(final BaseHandler baseHandler){
        this.baseHandler = baseHandler;
    }

    @Override
    protected Object extractInput(RoutingContext rc) {
        JsonObject jsonObject = (JsonObject) baseHandler.extractInput(rc);
        populateFileObjects(rc).ifPresent(jsonArray -> json.put("fileUploads", jsonArray));
        return jsonObject
    }
}

而且测试会更清楚:

@InjectMocks
ChildHandler testObj;

@Mock
BaseHandler baseHandlerMock;

@Mock
RoutingContext routingContextMock;

@Test
public void extractInputTest() {
    
    JsonObject jsonObject = new JsonObject();
    jsonObject.put("key", "value");

    JsonArray jsonArray = new JsonArray();
    JsonObject fileObject = new JsonObject();
    fileObject.put("fileName", "name");
    jsonArray.add(fileObject);
    Optional<JsonArray> optional = Optional.of(jsonArray);

    when(baseHandlerMock.extractInput(routingContextMock)).thenReturn(routingContextMock);
    doReturn(optional).when(handler).populateFileObjects(routingContextMock);

    Object o = handler.extractInput(routingContextMock);
    Map<String, Object> map = ((JsonObject) o).getMap();

    Assert.assertEquals("value", ((JsonObject)o).getString("key"));
    Assert.assertEquals(2, map.size()); //Junit fails here
    Assert.assertEquals(JsonArray.class, map.get("fileUploads").getClass());
    Assert.assertEquals(fileObject, ((JsonArray)map.get("fileUploads")).getJsonObject(0));
}