从服务中,我使用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交换调用工作吗?
验证需要在对生产代码的调用之后进行,在您的情况下是createLead()
调用。你还想在你的电话中使用匹配器,这可能不应该被评论掉。在像你这样的情况下,你通常不需要时间和验证。这只会使测试变得更加复杂和难以阅读。
如果我可以断言的服务调用没有返回,我会使用verify。在这种情况下,我会将when的所有参数(如果需要通过空指针异常或其他错误)包装在any()中,如any(HttpEntity.class)
或anyString()
,这样参数就不会含糊不清。然后,您可以使用验证来确认实际参数是否正确。这种策略更易于维护。不幸的是,它通常需要一个参数捕获器来验证头或其他参数是否正确发送。我说这很不幸,因为测试变得又大又乱,
如果我能断言结果,我通常只使用when。在这种情况下,我会用eq()
来包装params,比如eq(httpEntity)
。在这种情况下,HttpEntity类需要有一个好的.equals()
方法,或者它只使用默认方法,可能没有太大帮助。但是,它通常相当强大。
您不应该在设置中使用@InjectMocks
和initialize。如果您@InjectMocks
,它将创建实例并注入mock。你似乎想放一个真正的配置,这样你就可以使用setup方法,或者你可以模拟配置。我使用了一个正确的匹配器,但您可能需要对其进行改进,例如,将一些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));
}
}
您需要告诉Mockito在调用mock时返回什么。。。
when(restTemplate.exchange(anyString(), any(), any(), any())).thenReturn(...
在thenReturn中插入您希望从要交换的呼叫中返回的responseEntity。
@DCTID代码拯救了我的一天。除此之外,我还面临以下问题并进行了修复。为了模拟ResponseEntity的主体,我创建了一个对象并为其设置值。否则,它不会传递这个条件-if(exchange.getBody()!=空&;exchange.getBody().success)
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));