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

Unit testing 如何为Rest模板编写Mockito Junit测试用例?,unit-testing,spring-boot,junit,mockito,resttemplate,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

从服务中,我使用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);
}
}
@RunWith(MockitoJUnitRunner.class)
公共类强制服务测试{
@注射模拟
私人部队服务部队服务;
@嘲弄
私有RestTemplate RestTemplate;
@以前
公共作废设置(){
forceService=新的forceService(配置,restTemplate);
}
@试验
public void createTest_valid()抛出JSONException{
/*when(restemplate.exchange(url,HttpMethod.POST,entity,CreateRecordResult.class))
.然后返回(应答)*/
验证(restemplate,Mockito.times(1))
.exchange(Mockito.anyString(),
Mockito.any(),
Mockito.>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());
    }
@组件
公共服务{
私有RestTemplate RestTemplate;
公共ForceService(ForceServiceConfig配置,RestTemplate RestTemplate){
this.config=config;
this.restTemplate=restTemplate;
}
公共字符串createLead(Lead-Lead){
HttpHeaders=新的HttpHeaders();
set(授权,getAccessToken());
headers.set(ACCEPT,APPLICATION_JSON);
headers.set(内容类型、应用程序类型);
引线包裹引线包裹=新引线包裹();
leadWrap.setFirstName(lead.getFirstName());
leadWrap.setLastName(lead.getLastName());
leadWrap.setEmail(lead.getEmail());
leadWrap.setPhone(lead.getPhone());
字符串jsonString;
试一试{
jsonString=newObjectMapper().writeValueAsString(leadWrap);
}捕获(IOE异常){
抛出新的运行时异常(e);
}
HttpEntity=新的HttpEntity(jsonString,头文件);
ResponseEntity exchange=restTemplate.exchange(
config.restUrl+“/v”+config.restVersion+“/sobjects/Lead/”,HttpMethod.POST,实体,
CreateRecordResult.class);
if(exchange.getStatusCode().equals(HttpStatus.CREATED)){
if(exchange.getBody()!=null&&exchange.getBody().success){
LOGGER.info(“使用Id+exchange.getBody().Id创建的Lead记录”);
返回exchange.getBody().id;
}
抛出新的RuntimeException(“未创建记录”);
}否则{
LOGGER.error(RETURN_STATUS+exchange.getStatusCode());
抛出新的运行时异常(返回_STATUS+exchange.getStatusCode());
}

上面的测试用例将ResponseEntity exchange返回为null。有没有解决方案可以使测试用例在RestTemplate exchange调用中工作?

您需要告诉Mockito调用mock时返回什么

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

在thenReturn中插入您希望从对exchange的调用中返回的responseEntity。

验证需要在对生产代码的调用之后进行,在您的示例中是
createLead()
call。您还需要在when调用中使用匹配器,这可能不应该被注释掉。在像您这样的情况下,您通常不需要when和verify。这只会使测试更复杂,更难阅读

我使用verify if the verify if not return from service call,我可以对其进行断言。在这种情况下,我会将when的所有参数(如果需要通过空指针异常或其他错误)包装在任何()中,例如
any(HttpEntity.class)
anyString()
这样参数就不会模棱两可。然后您可以使用verify来确认实际参数是否正确。这种策略更易于维护。不幸的是,它通常需要一个参数捕获器来验证标头或其他参数是否正确发送。我说这很不幸,因为测试变得庞大而混乱

如果我可以在结果上断言,我通常只使用when。在这种情况下,我将使用
eq()
包装参数,例如
eq(httpEntity)
。在这种情况下,httpEntity类需要有一个好的
.equals()
方法,或者它只使用默认值,可能没有多大帮助。但是,它通常非常强大

你不应该在设置中使用
@InjectMocks
并进行初始化。如果你
@InjectMocks
它会创建实例并注入mock。你似乎想放入一个真实的配置,以便使用安装方法或模拟配置。我使用了一个正确的匹配器,但你可能必须对它们进行优化,例如切换一些
 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));
    }
}
import org.junit.Before;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.mockito.Mock;
导入org.mockito.runners.MockitoJUnitRunner;
导入org.springframework.http.HttpEntity;
导入org.springframework.http.HttpMethod;
导入org.springframework.http.HttpStatus;
导入org.springframework.http.ResponseEntity;
导入org.springframework.web.client.rest模板;
导入静态org.mockito.Matchers.*;
导入静态org.mockito.mockito.*;
@RunWith(MockitoJUnitRunner.class)
公共类强制服务测试{
私人部队服务部队服务;
@嘲弄
私有RestTemplate RestTemplate;
@以前
公共作废设置(){
forceService=新的forceService(新的ForceServiceConfig(),restTemplate);
}
@试验
public void createTest_valid()引发异常{
当(restemplate.exchange(anyString(),eq(HttpMethod.POST)),
任何(HttpEntity.class),
eq(CreateRecordResult.class)))
.thenReturn(新的ResponseEntity(新的CreateRecordResult(),HttpStatus.CREATED));
createLead();
验证(REST模板,次数(1))
.exchange(eq(“config.restUrl/vconfig.restVersion/sobjects/Lead/”),
CreateRecordResult createRecordResult = new CreateRecordResult();
createRecordResult.success = true;
Mockito.when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class),
            eq(CreateRecordResult.class)))
                    .thenReturn(new ResponseEntity<>(createRecordResult, HttpStatus.CREATED));