Java 如何在 mockmvc 中将模拟对象作为 JSON 发送

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24199393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 10:45:18  来源:igfitidea点击:

How to send a mock object as JSON in mockmvc

javajsonunit-testinggsonmockito

提问by Sourabh

I want to send a mock object in the controller via MockMvc with content type JSON. But when I am trying to serialize the mock the error is:

我想通过 MockMvc 在控制器中发送一个内容类型为 JSON 的模拟对象。但是当我尝试序列化模拟时,错误是:

java.lang.UnsupportedOperationException: Expecting parameterized type, got interface org.mockito.internal.MockitoInvocationHandler.
 Are you missing the use of TypeToken idiom?

My code is as following:

我的代码如下:

@Test
public void testSomething(){

    String xyz = "";
    Integer i = 10;
    SomeClass inst = mock(SomeClass.class, withSettings().serializable());
    when(inst.getProperty1()).then(xyz);
    when(inst.getProperty2()).then(i);

    Gson gson = new Gson();
    String json = gson.toJson(inst); // this is creating error

    this.mockmvc.perform(put("/someUrl/").contentType(MediaType.JSON).content(json)).andExpect(status().isOk());
}

Can someone tell me what I'm missing?

有人可以告诉我我错过了什么吗?

采纳答案by matsev

I propose that you create a stubof your SomeClassthat returns known values for the getProperty1()and getProperty2()method. Depending on how SomeClassis implemented, you could either create a newinstance of it directly, subclass and override some methods, create an anonymous inner class if it is an interface, etc.

我建议您创建一个存根,该存根SomeClassgetProperty1()andgetProperty2()方法返回已知值。根据SomeClass实现方式,您可以new直接创建它的实例,子类化并覆盖某些方法,如果它是接口,则创建一个匿名内部类等。

@Test
public void testSomething(){

    String xyz = "";
    Integer i = 10;

    // alt 1:
    SomeClass stub = new SomeClass(xyz, i);

    // alt 2: 
    SomeClass stub = new StubSomeClass(xyz, i); // StubSomeClass extends SomeClass

    // alt 3: 
    SomeClass stub = new SomeClass() {
         @Override
         String getProperty1() {
             return xyz;
         }
         @Override
         Integer getProperty2() {
             return i;
         }
    }

    Gson gson = new Gson();
    String json = gson.toJson(stub);

    this.mockmvc.perform(put("/someUrl/")
        .contentType(MediaType.APPLICATION_JSON).content(json))
        .andExpect(status().isOk());
}

回答by Serge Ballesta

Even if it was possible, submitting a mock object to a JSON converter would suppose a unit test dedicated to that operation : the mock object may have many attributes and methods far beyond the real class and the serialization could lead to a really strangeresult.

即使有可能,将模拟对象提交给 JSON 转换器也会假设一个专用于该操作的单元测试:模拟对象可能具有远远超出真实类的许多属性和方法,并且序列化可能会导致非常奇怪的结果。

IMHO, as it is a unit test, you should write by hand the json serialized String. And you can do other tests if you need to control how Gson does the serialization

恕我直言,因为它是一个单元测试,你应该手工编写 json 序列化字符串。如果您需要控制 Gson 如何进行序列化,您可以进行其他测试

回答by Sourabh

I did find a way to serialize a mock object in a following manner:

我确实找到了一种以下列方式序列化模拟对象的方法:

Gson gson = new GSon();
String json = gson.toJson(mockedObject, mockedObjectType.class);

Although what I was trying was a USELESS case since json will be stripped of all the mocking i have provided in the test() function thereby when the object will be rebuilt it will have no value of mocking to it and will throw NullPointerException at the first instance of usage of any function/property.

虽然我尝试的是一个无用的案例,因为 json 将被剥夺我在 test() 函数中提供的所有模拟,因此当对象将被重建时,它将没有模拟它的价值,并且会首先抛出 NullPointerException任何函数/属性的使用实例。

EDIT : If you want to serialize nulls there is a function for that too :

编辑:如果你想序列化空值,也有一个函数:

Gson gson = new GsonBuilder().serializeNulls().create();

回答by virtual agent 07

We had a similar issue: there was logging statement for outputting an object serialized to json. And unit test case for this produced error because gson couldn't serialize mock object. It was solved with providing exclusion strategy that skips serializing Class and fields of type Class:

我们有一个类似的问题:有用于输出序列化为 json 的对象的日志记录语句。这个单元测试用例产生了错误,因为 gson 无法序列化模拟对象。通过提供跳过序列化 Class 和 Class 类型的字段的排除策略解决了这个问题:

 private final Gson gson = new GsonBuilder()
     .setExclusionStrategies(new ExclusionStrategy() {
    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return clazz instanceof Class;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes field) {
        return field.getDeclaredClass() == Class.class;
    }
}).create();

回答by exe_sys

In test configuration you may wrap default message converter with another message converter which supports serialization of any object into String.

在测试配置中,您可以使用另一个支持将任何对象序列化为字符串的消息转换器包装默认消息转换器。

package com.example;

import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;

import java.io.IOException;
import java.util.Arrays;

public class MockObjectHttpMessageConverter extends AbstractHttpMessageConverter {


  private final AbstractHttpMessageConverter primaryConverter;

  public MockObjectHttpMessageConverter(AbstractHttpMessageConverter primaryConverter) {
    this.primaryConverter = primaryConverter;
    setSupportedMediaTypes(Arrays.asList(MediaType.ALL));
  }

  @Override
  protected boolean supports(Class clazz) {
    return true;
  }

  @Override
  protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
    throw new UnsupportedOperationException();
  }

  @Override
  protected void writeInternal(Object o, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
    try {
      primaryConverter.write(o, MediaType.ALL, outputMessage);
    } catch (Exception e) {
      IOUtils.write(o.toString(), outputMessage.getBody());
    }
  }
}

In Spring's context XML put:

在 Spring 的上下文 XML 中:

<mvc:message-converters>
    <bean class="com.example.MockObjectHttpMessageConverter">
        <constructor-arg>
            <bean class="org.springframework.http.converter.json.GsonHttpMessageConverter">
                <property name="gson">
                    <bean class="com.google.gson.Gson" factory-bean="gsonBuilder" factory-method="create"/>
                </property>
            </bean>
        </constructor-arg>
    </bean>
</mvc:message-converters>