我有一项服务,我需要通过休息向外部服务器询问一些信息:
public class SomeService {
public List<ObjectA> getListofObjectsA() {
List<ObjectA> objectAList = new ArrayList<ObjectA>();
ParameterizedTypeReference<List<ObjectA>> typeRef = new ParameterizedTypeReference<List<ObjectA>>() {};
ResponseEntity<List<ObjectA>> responseEntity = restTemplate.exchange("/objects/get-objectA", HttpMethod.POST, new HttpEntity<>(ObjectAList), typeRef);
return responseEntity.getBody();
}
}
如何为getListofObjectsA()
编写JUnit测试?
我尝试过以下内容:
@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
private MockRestServiceServer mockServer;
@Mock
private RestTemplate restTemplate;
@Inject
private SomeService underTest;
@Before
public void setup() {
mockServer = MockRestServiceServer.createServer(restTemplate);
underTest = new SomeService(restTemplate);
mockServer.expect(requestTo("/objects/get-objectA")).andExpect(method(HttpMethod.POST))
.andRespond(withSuccess("{json list response}", MediaType.APPLICATION_JSON));
}
@Test
public void testGetObjectAList() {
List<ObjectA> res = underTest.getListofObjectsA();
Assert.assertEquals(myobjectA, res.get(0));
}
但是,上述代码不起作用,表明responseEntitty
为null
。如何更正我的测试以正确模拟restTemplate.exchange
?
答案 0 :(得分:22)
您不需要MockRestServiceServer
个对象。注释为@InjectMocks
而非@Inject
。下面是一个应该起作用的示例代码
@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
@Mock
private RestTemplate restTemplate;
@InjectMocks
private SomeService underTest;
@Test
public void testGetObjectAList() {
ObjectA myobjectA = new ObjectA();
//define the entity you want the exchange to return
ResponseEntity<List<ObjectA>> myEntity = new ResponseEntity<List<ObjectA>>(HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(
Matchers.eq("/objects/get-objectA"),
Matchers.eq(HttpMethod.POST),
Matchers.<HttpEntity<List<ObjectA>>>any(),
Matchers.<ParameterizedTypeReference<List<ObjectA>>>any())
).thenReturn(myEntity);
List<ObjectA> res = underTest.getListofObjectsA();
Assert.assertEquals(myobjectA, res.get(0));
}
答案 1 :(得分:15)
ResponseEntity<String> responseEntity = new ResponseEntity<String>("sampleBodyString", HttpStatus.ACCEPTED);
when(restTemplate.exchange(
Matchers.anyString(),
Matchers.any(HttpMethod.class),
Matchers.<HttpEntity<?>> any(),
Matchers.<Class<String>> any()
)
).thenReturn(responseEntity);
答案 2 :(得分:9)
这是一个未经处理的ArgumentMatchers类
的示例when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
答案 3 :(得分:4)
对我来说,我不得不使用Matchers.any(URI.class)
Mockito.when(restTemplate.exchange(Matchers.any(URI.class), Matchers.any(HttpMethod.class), Matchers.<HttpEntity<?>> any(), Matchers.<Class<Object>> any())).thenReturn(myEntity);
答案 4 :(得分:2)
这项工作在我身边。
ResourceBean resourceBean = initResourceBean();
ResponseEntity<ResourceBean> responseEntity
= new ResponseEntity<ResourceBean>(resourceBean, HttpStatus.ACCEPTED);
when(restTemplate.exchange(
Matchers.anyObject(),
Matchers.any(HttpMethod.class),
Matchers.<HttpEntity> any(),
Matchers.<Class<ResourceBean>> any())
).thenReturn(responseEntity);
答案 5 :(得分:1)
假设您像下面这样进行通话:
String url = "/zzz/{accountNumber}";
Optional<AccountResponse> accResponse = Optional.ofNullable(accountNumber)
.map(account -> {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "bearer 121212");
HttpEntity<Object> entity = new HttpEntity<>(headers);
ResponseEntity<AccountResponse> response = template.exchange(
url,
GET,
entity,
AccountResponse.class,
accountNumber
);
return response.getBody();
});
要在测试用例中对此进行模拟,可以按以下方式使用mocitko:
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<AccountResponse>>any(),
ArgumentMatchers.<ParameterizedTypeReference<List<Object>>>any())
)
答案 6 :(得分:0)
我实施了非常有用的a small library。它提供了ClientHttpRequestFactory
,可以接收一些上下文。通过这样做,它允许遍历所有客户端层,例如检查查询参数是否已被评估,标头设置,以及检查反序列化是否正常。
答案 7 :(得分:0)
如果您的意图是测试服务而不关心其余的调用,我建议您不要在单元测试中使用任何注释来简化测试。
所以,我的建议是重构你的服务以使用注入构造函数接收resttemplate。这将有助于测试。例如:
area_id FK
将RestTemplate作为组件,在以下情况下进行注入和模拟:
@Service
class SomeService {
@AutoWired
SomeService(TestTemplateObjects restTemplateObjects) {
this.restTemplateObjects = restTemplateObjects;
}
}
测试:
@Component
public class RestTemplateObjects {
private final RestTemplate restTemplate;
public RestTemplateObjects () {
this.restTemplate = new RestTemplate();
// you can add extra setup the restTemplate here, like errorHandler or converters
}
public RestTemplate getRestTemplate() {
return restTemplate;
}
}
通过这种方式,您可以直接访问SomeService构造函数来模拟其余模板。
答案 8 :(得分:0)
RestTemplate
实例必须是真实的对象。如果创建RestTemplate
的真实实例并将其设置为@Spy
,它应该可以工作。
@Spy
private RestTemplate restTemplate = new RestTemplate();
答案 9 :(得分:0)
如果您使用的是RestTemplateBuilder
,则可能无法正常进行。您需要将其与when(condition)一起添加到测试类中。
@Before
public void setup() {
ReflectionTestUtils.setField(service, "restTemplate", restTemplate);
}
答案 10 :(得分:0)
我曾经遇到过这样的错误。我找到了更可靠的解决方案。我也提到了对我有用的导入声明。下面的代码完美地模拟了模板。
导入org.mockito.Matchers;
导入静态org.mockito.Matchers.any;
HttpHeaders headers = new Headers();
headers.setExpires(10000L);
ResponseEntity<String> responseEntity = new ResponseEntity<>("dummyString", headers, HttpStatus.OK);
when(restTemplate.exchange( Matchers.anyString(),
Matchers.any(HttpMethod.class),
Matchers.<HttpEntity<?>> any(),
Matchers.<Class<String>> any())).thenReturn(responseEntity);
答案 11 :(得分:0)
如果仍然有人遇到此问题,Captor注释对我有用
@Captor
private ArgumentCaptor<Object> argumentCaptor;
然后我可以通过以下方式模拟请求:
ResponseEntity<YourTestResponse> testEntity = new ResponseEntity<>(
getTestFactoryResponse(),
HttpStatus.OK);
when(mockRestTemplate.exchange((String) argumentCaptor.capture(),
(HttpMethod) argumentCaptor.capture(),
(HttpEntity<?>) argumentCaptor.capture(),
(Class<YourTestResponse.class>) any())
).thenReturn(testEntity);
答案 12 :(得分:0)
如果有人在尝试模拟 restTemplate.exchange(...) 时遇到此问题,则问题似乎出在匹配器上。例如:以下内容不起作用,
when(ecocashRestTemplate.exchange(Mockito.any()
, Mockito.eq(HttpMethod.GET)
, Mockito.any(HttpEntity.class)
, Mockito.<Class<UserTransaction>>any())
).thenReturn(new ResponseEntity<>(transaction, HttpStatus.OK));
但这个确实有效:
ResponseEntity<UserTransaction> variable = new ResponseEntity<>(transaction, HttpStatus.OK);
when(ecocashRestTemplate.exchange(Mockito.anyString()
, Mockito.eq(HttpMethod.GET)
, Mockito.any(HttpEntity.class)
, Mockito.<Class<UserTransaction>>any())
).thenReturn(new ResponseEntity<>(transaction, HttpStatus.OK));
注意第二个块上的 Mockito.anyString() 与 theMockito.any()。
答案 13 :(得分:0)
当我们测试使用 restTemplate 与某个外部系统通信的客户端时,作为单元测试的一部分,我们需要验证我们发送的 httpEntity、标头和参数。
ArgumentCaptor 在这些情况下派上用场。所以这是我的例子(工作代码)
@Mock
private RestTemplate restTemplate;
@InjectMocks
private MyClient client;
@Captor
ArgumentCaptor<HttpEntity<?>> httpEntityCaptor;
when(restTemplate.exchange(eq(expectedUrl), eq(HttpMethod.POST), Matchers.any(HttpEntity.class), eq(MyTargetResponse.class)).thenReturn(expectedResponse);
verify(restTemplate).exchange(eq(expectedUrl),eq(HttpMethod.POST), httpEntityCaptor.captor(),eq(MyTargetResponse.class));
HttpEntity<?> actualResponse = httpEntityCaptor.getValue();
HttpHeaders actualResponse.getHeaders();
assertEquals(headers.getFirst("Content-Type", "application/json")
现在可以根据您的用例做出断言,因为您已经获得了发送的捕获对象。