如何为Rest模板编写Mockito Junit测试用例?

时间:2019-01-28 02:20:32

标签: unit-testing spring-boot junit mockito resttemplate

从服务中,我使用RestTemplate调用第三方api。

@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
@InjectMocks
private ForceService forceService;
@Mock
private RestTemplate restTemplate;
@Before
public void setup() {
    forceService = new ForceService(config, restTemplate);
}
@Test
public void createTest_valid() throws JSONException {
    /*Mockito.when(restTemplate.exchange(url, HttpMethod.POST, entity, CreateRecordResult.class))
    .thenReturn(response);*/
     Mockito.verify(restTemplate, Mockito.times(1))
    .exchange(Mockito.anyString(),
                    Mockito.<HttpMethod> any(),
                    Mockito.<HttpEntity<?>> any(),
                    Mockito.<Class<?>> any());
    forceService.createLead(lead);
}
}

我尝试同时使用any()方法和直接指定值。在实体中直接指定值似乎不是正确的测试方法。 下面是我需要为其编写测试用例的服务类。

@Component
public class ForceService {
    private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,  RestTemplate restTemplate) {
    this.config = config;
    this.restTemplate = restTemplate;
}
public String createLead(Lead lead) {
    HttpHeaders headers = new HttpHeaders();
    headers.set(AUTHORIZATION, getAccessToken());
    headers.set(ACCEPT, APPLICATION_JSON);
    headers.set(CONTENT_TYPE, APPLICATION_JSON);
    LeadWrap leadWrap = new LeadWrap();
    leadWrap.setFirstName(lead.getFirstName());
    leadWrap.setLastName(lead.getLastName());
    leadWrap.setEmail(lead.getEmail());
    leadWrap.setPhone(lead.getPhone());

    String jsonString;
    try {
        jsonString = new ObjectMapper().writeValueAsString(leadWrap);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);

    ResponseEntity<CreateRecordResult> exchange = restTemplate.exchange(
            config.restUrl + "/v" + config.restVersion + "/sobjects/Lead/", HttpMethod.POST, entity,
            CreateRecordResult.class);
    if (exchange.getStatusCode().equals(HttpStatus.CREATED)) {
        if (exchange.getBody() != null && exchange.getBody().success) {
            LOGGER.info("Lead record created with Id " + exchange.getBody().id);
            return exchange.getBody().id;
        }
        throw new RuntimeException("Record is not created");
    } else {
        LOGGER.error(RETURN_STATUS + exchange.getStatusCode());
        throw new RuntimeException(RETURN_STATUS + exchange.getStatusCode());
    }

以上测试用例将ResponseEntity交换返回为null。有什么解决方案可以使测试用例适用于RestTemplate交换调用?

3 个答案:

答案 0 :(得分:0)

您需要告诉Mockito调用模拟程序时返回什么...

when(restTemplate.exchange(anyString(), any(), any(), any())).thenReturn(...

将要从调用中返回的responseEntity插入到thenReturn中进行交换。

答案 1 :(得分:0)

在调用生产代码(在您的情况下为createLead()调用)之后,需要进行验证。您还将要在呼叫时使用匹配器,这可能不应该被注释掉。在像您这样的情况下,通常不需要时间和验证。这只会使测试更加复杂且难以阅读。

我使用验证是否可以确定的服务调用没有返回。在那种情况下,我会将when的所有参数(如果需要克服空指针异常或其他错误)包装在any()中,例如any(HttpEntity.class)anyString(),这样参数就不会模棱两可。然后,您可以使用验证来确认实际参数正确。此策略更易于维护。不幸的是,通常需要参数捕获器来验证标头或其他参数是否正确发送。我说这很不幸,因为测试变得又大又混乱,

如果我可以断言结果,那么我通常只使用when。在那种情况下,我将用eq()来包装参数,例如eq(httpEntity)。在这种情况下,HttpEntity类将需要具有良好的.equals()方法,或者仅使用默认方法,可能并不是很有用。但是,它通常非常强大。

您不应使用@InjectMocks并在设置中进行初始化。如果您@InjectMocks,它将创建实例并注入模拟。您似乎想放置一个真实的配置,因此可以使用设置方法,也可以模拟该配置。我使用了正确的匹配器,但是您可能需要对其进行优化,例如将某些any()切换为eq()才能真正测试您要测试的内容。我还进行了重新排序,因此操作或生产调用已在验证之前进行。该测试应该可以帮助您入门。

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {

    private ForceService forceService;
    @Mock
    private RestTemplate restTemplate;

    @Before
    public void setup() {
        forceService = new ForceService(new ForceServiceConfig(), restTemplate);
    }

    @Test
    public void createTest_valid() throws Exception {
        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST),
                any(HttpEntity.class),
                eq(CreateRecordResult.class)))
                .thenReturn(new ResponseEntity<>(new CreateRecordResult(), HttpStatus.CREATED));

        forceService.createLead();

        verify(restTemplate, times(1))
                .exchange(eq("config.restUrl/vconfig.restVersion/sobjects/Lead/"),
                        any(HttpMethod.class),
                        any(HttpEntity.class),
                        eq(CreateRecordResult.class));
    }
}

答案 2 :(得分:0)

@DCTID代码保存了我的一天。随之而来的是我面对以下问题并予以解决。 为了模拟ResponseEntity的主体,我创建了一个对象并为其设置值。否则,它没有通过此条件-if(exchange.getBody()!= null && exchange.getBody()。success)

var util = require("util");
console.log(util.inspect(myObject, {showHidden: false, depth: null}));