I would like to mock an object passed into Gson via TypeAdapter like this:
@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;
}
}
My type adapter:
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;
}
}
But I end up which such exception:
java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: com.editor.api.scene.objects.SceneObject. Forgot to register a type adapter?
Scene object is pretty heavy object and I don't want to instantinate it normally within test. So is there a possibility to just mock it? I also would like not to use Spies.
The runtime type of an instance of SceneObject
created in this way: mock(SceneObject.class)
is SceneObject$MockitoMock$<SOMEID>
.
The runtime type of an instance of SceneObject
created in this way: new SceneObject()
is SceneObject
.
So, when Gson's TypeAdapterRuntimeTypeWrapper
looks for a registered TypeAdapter
in its context for a mocked object it will not find one because your SceneExporter
has been registered against SceneObject.class
.
What this is really saying is that a mocked SceneObject
is not of type SceneObject
(it is actually a sub class of SceneObject
) hence Gson will not find your bespoke type adapter.
If you declare Gson
like this ...
Gson gson = new GsonBuilder().registerTypeAdapter(mock(SceneObject.class).getClass(), new SceneExporter()).create();
... then it will find your bespoke type adapter but that registration looks 'off' doesn't it? It feels like a test-only specialisation.
If you really must mock SceneObject
then I think you'll need to register an inheritance aware type adapter but if you are doing that just to support this test case then that feels like a test-only limitation bleeding into the 'main' source tree. So, perhaps the simplest solutions are:
SceneObject
Spy
to stub out the specific SceneObject
getters which are invoked in SceneExporter
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.