java - 如何将 Gson TypeAdapter 与 Mockito 模拟的对象一起使用?

标签 java unit-testing gson mockito

我想像这样通过 TypeAdapter 模拟一个传递给 Gson 的对象:

@RunWith(MockitoJUnitRunner.class)
public class SceneExporterTest {

@Test
public void testWriter() {
    List<SceneObject> sceneObjects = mockSceneObjects();
    Gson gson = new GsonBuilder().registerTypeAdapter(SceneObject.class, new SceneExporter()).create();

    String s = gson.toJson(sceneObjects); //This method ends up with an exception.
}

private List<SceneObject> mockSceneObjects() {
    List<SceneObject> sceneObjects = new LinkedList<>();
    for (int i = 0; i < 50; i++) {
        sceneObjects.add(mockSceneObject(i));
    }
    return sceneObjects;
}

private SceneObject mockSceneObject(int i) {
    SceneObject sceneObject = mock(SceneObject.class);
    //...
    return sceneObject;
}

}

我的类型适配器:

public class SceneExporter extends TypeAdapter<SceneObject> {

    @Override
    public void write(JsonWriter out, SceneObject value) throws IOException {
        out.name("position");
        out.value(toValue(value.getPosition()));
        out.name("scale");
        out.value(toValue(value.getScale()));
        out.name("rotation");
        out.value(toValue(value.getRotation()));
    }

    @Override
    public SceneObject read(JsonReader in) throws IOException {
        return null;
    }
}

但我最终得到了这样的异常:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.editor.api.scene.objects.SceneObject. Forgot to register a type adapter?

场景对象是非常重的对象,我不想在测试中正常实例化它。那么有可能只是 mock 它吗?我也不想使用 Spies。

最佳答案

SceneObject 实例的运行时类型以这种方式创建:mock(SceneObject.class)SceneObject$MockitoMock$<SOMEID> .

SceneObject 实例的运行时类型以这种方式创建:new SceneObject()SceneObject .

所以,当 Gson 的 TypeAdapterRuntimeTypeWrapper寻找已注册的 TypeAdapter在模拟对象的上下文中,它找不到一个,因为你的 SceneExporter已针对 SceneObject.class 注册.

这实际上是在说一个模拟的 SceneObject不是类型 SceneObject (它实际上是 SceneObject 的子类)因此 Gson 不会找到您定制的类型适配器。

如果声明Gson像这样……

Gson gson = new GsonBuilder().registerTypeAdapter(mock(SceneObject.class).getClass(), new SceneExporter()).create();

...然后它找到您定制的类型适配器,但注册看起来“关闭”,不是吗?感觉就像是只应试的专业。

如果你真的必须模拟SceneObject那么我想你需要注册一个 inheritance aware type adapter但是如果你这样做只是为了支持这个测试用例,那么感觉就像是一个只用于测试的限制渗入了“主”源代码树。因此,也许最简单的解决方案是:

  • 创建 SceneObject 的真实实例
  • 使用 Mockito Spy去掉特定的SceneObjectSceneExporter 中调用的 setter/getter

关于java - 如何将 Gson TypeAdapter 与 Mockito 模拟的对象一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46142309/

相关文章:

scala - Specs2 - 如何吞掉异常

unit-testing - 自测系统

java - 使用gson解析不同类型的Json对象

java - 在/上找不到资源上的 SpringMVC Controller

java - 如何使用 DB 为方法创建 jUnit 测试用例

java - Json 反序列化日期不起作用

java - Retrofit 无法正确解析 body

java - 使用 gson 解析带有变体键值的 json 到 hashmap

java - 创建和运行 Java 小程序

java - 尝试每个标准 lib 选项后从 java 执行 sudo 命令