【问题标题】:How to write mockito junit for Resttemplate postForObject method如何为 Resttemplate postForObject 方法编写 mockito junit
【发布时间】:2018-05-15 10:20:50
【问题描述】:

我正在尝试将消息列表发布到其余 api。如何为下面的方法 postJSONData 编写 mockito junit:

public class PostDataService{

    @Autowired
    RestTemplate restTemplate;

    @Autowired
    private Environment env;

    private HttpEntity<String> httpEntity;

    private HttpHeaders httpHeaders;

    private String resourceURL = null;

    public PostDataService(){
    httpHeaders = new HttpHeaders();
    httpHeaders.set("Content-Type", "application/json");
    }

    public void postJSONData(List<String> data){
    try
    {
    resourceURL = env.getProperty("baseURL") + env.getProperty("resourcePath");
    httpEntity = new HttpEntity<String>(data.toString(), httpHeaders);
    String response = restTemplate.postForObject(resourceURL, httpEntity, String.class);
    }
    catch (RestClientException e) {
            LOGGER.info("ErrorMessage::" + e.getMessage());
            LOGGER.info("ErrorCause::" + e.getCause());
        }
    } 


}

请帮我写一下。

【问题讨论】:

  • 问题是:你想测试什么?
  • @Stefan Birkner:我想模拟服务并测试 postJSONData 方法。在这种情况下,resourceURL 包含我通过发送正文中的消息列表并查看是否可以捕获响应状态代码来发出发布请求的实际服务。在这种情况下我需要使用 MockRestServiceServer 吗?

标签: java spring junit mockito resttemplate


【解决方案1】:

您可以使用 Mockito 来:

  • 使用模拟的RestTemplateEnvironment 创建postData 的实例
  • 对允许 ``postJSONData` 调用完成的这些设置期望
  • 验证模拟的RestTemplate 是否被正确调用

postJSONData 方法不使用 restTemplate.postForObject() 响应,因此在测试此方法方面您能做的最好的事情是验证 restTemplate.postForObject() 是否使用正确的参数调用。

这是一个例子:

@RunWith(MockitoJUnitRunner.class)
public class PostDataTest {

    @Mock
    private RestTemplate restTemplate;
    @Mock
    private Environment env;

    @InjectMocks
    private PostData postData;

    @Test
    public void test_postJSONData() {
        String baseUrl = "theBaseUrl";
        String resourcePath = "aResourcePath";

        Mockito.when(env.getProperty("baseURL")).thenReturn(baseUrl);
        Mockito.when(env.getProperty("resourcePath")).thenReturn(resourcePath);

        List<String> payload = new ArrayList<>();

        postData.postJSONData(payload);

        // it's unclear from your posted code what goes into the HttpEntity so
        // this approach is lenient about its expectation
        Mockito.verify(restTemplate).postForObject(
                Mockito.eq(baseUrl + resourcePath),
                Mockito.any(HttpEntity.class),
                Mockito.eq(String.class)
        );

        // assuming that the HttpEntity is constructed from the payload passed 
        // into postJSONData then this approach is more specific
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json");
        Mockito.verify(restTemplate).postForObject(
                Mockito.eq(baseUrl + resourcePath),
                Mockito.eq(new HttpEntity<>(payload.toString(), headers)),
                Mockito.eq(String.class)
        );
    }
}

附带说明; postData 是一个不寻常的类名称,您的 OP 中提供的 postJSONData 方法无法编译;它引用meterReadings 而不是data

【讨论】:

  • 我尝试了这种方法并面临以下错误想要但未调用想要但未调用:restTemplate.postForObject("localhost:8080/updateOperation", , class java.lang.String );实际上,与这个 mock 的交互为零。
  • 您能否通过调试确认postJSONData 中使用的RestTemplate 实例肯定是模拟的?
  • 这是可行的,但是如果我想在发出发布请求后验证响应状态代码会是什么情况?
  • 就目前情况而言,您不会返回响应代码,因此无法对其进行验证。如果您对 postJSONData 进行了重新设计以使其返回响应代码,那么您可以在测试中执行以下操作:String response = postData.postJSONData(payload); assertEquals(expectedResponse, reponse);
  • 虽然,当然,因为你在嘲笑 'RestTemplate' 断言它的返回值是有限的用处。
【解决方案2】:

您可以使用wiremock 模拟服务器。这是一个专门针对这项工作的模拟框架。

在您的 pom.xml 中添加以下依赖项:

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>2.12.0</version>
</dependency>

在您的测试中添加以下规则:

@Rule
public WireMockRule wireMockRule = new WireMockRule(); // default port is 8080

然后您应该在application.properties(或其他地方)中定义您的baseUrlresourcePath 属性。请记住,服务器将在 localhost 上运行。

之后,您应该模拟资源路径的 HTTP 响应:

stubFor(get(urlEqualTo(resourcePath))
            .withHeader("Accept", equalTo("application/json"))
            .willReturn(aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody(content)));

然后就可以执行 postJSONData 方法了:

postData.postJSONData();

最后,您可以验证对服务器的请求是否正确。

verify(postRequestedFor(urlMatching(resourcePath))
        .withRequestBody(matching(expectedBody))
        .withHeader("Content-Type", matching("application/json")));

【讨论】:

    【解决方案3】:

    正确模拟postForObject

        @ExtendWith(MockitoExtension.class)
        public class YourServiceTest {
            
                @Mock
                RestTemplate template;
            
                @InjectMocks
                private final YourService srv = new YourService();
            
            
                @Test
                public void yourTest() {
                    when(template.postForObject(anyString(),any(Object.class),eq(String.class)))
                            .thenReturn("xxxxxxxxxxx");
                    assertEquals("xxxxxxxxxxx", srv.yourMethod());
                }
            }
    

    【讨论】:

      猜你喜欢
      • 2015-08-30
      • 2018-03-04
      • 2014-07-08
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 2019-03-20
      • 1970-01-01
      相关资源
      最近更新 更多