Java 如何模拟 REST 模板交换?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39486521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I mock a REST template exchange?
提问by Akka Jaworek
I have a service in which I need to ask an outside server via rest for some information:
我有一项服务,我需要通过休息向外部服务器询问一些信息:
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();
}
}
How can I write a JUnit test for getListofObjectsA()
?
如何为 编写 JUnit 测试getListofObjectsA()
?
I have tried with the below:
我试过以下:
@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));
}
However the above code does not work, it shows that responseEntitty
is null
. How can I correct my test to properly mock restTemplate.exchange
?
但是上面的代码不起作用,它表明responseEntitty
是null
. 如何更正我的测试以正确模拟restTemplate.exchange
?
采纳答案by Mindaugas
You don't need MockRestServiceServer
object. The annotation is @InjectMocks
not @Inject
. Below is an example code that should work
你不需要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));
}
回答by Shyam Elakapalli
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);
回答by Abbin Varghese
For me, I had to use Matchers.any(URI.class)
对我来说,我不得不使用 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);
回答by Kier GRAY
I implemented a small librarythat is quite useful. It provides a ClientHttpRequestFactory
that can receive some context. By doing so, it allows to go through all client layers such as checking that query parameters are valued, headers set, and check that deserialization works well.
我实现了一个非常有用的小库。它提供了一个ClientHttpRequestFactory
可以接收一些上下文的。通过这样做,它允许遍历所有客户端层,例如检查查询参数是否已赋值、标头设置,并检查反序列化是否运行良好。
回答by Dherik
If your intention is test the service without care about the rest call, I will suggest to not use any annotation in your unit test to simplify the test.
如果您的意图是在不关心 rest 调用的情况下测试服务,我建议您不要在单元测试中使用任何注释来简化测试。
So, my suggestion is refactor your service to receive the resttemplate using injection constructor. This will facilitate the test. Example:
因此,我的建议是重构您的服务以使用注入构造函数接收 resttemplate。这将有助于测试。例子:
@Service
class SomeService {
@AutoWired
SomeService(TestTemplateObjects restTemplateObjects) {
this.restTemplateObjects = restTemplateObjects;
}
}
The RestTemplate as component, to be injected and mocked after:
RestTemplate 作为组件,在之后注入和模拟:
@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;
}
}
And the test:
和测试:
public void test() {
when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate);
//mock restTemplate.exchange
when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity);
SomeService someService = new SomeService(mockedRestTemplateObject);
someService.getListofObjectsA();
}
In this way, you have direct access to mock the rest template by the SomeService constructor.
通过这种方式,您可以通过 SomeService 构造函数直接访问模拟其余模板。
回答by chendu
This work on my side.
这在我这边工作。
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);
回答by itstata
This is an example with the non deprecated ArgumentMatchersclass
这是一个使用非弃用ArgumentMatchers类的示例
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
回答by Manoj Shrestha
The RestTemplate
instance has to be a real object. It should work if you create a real instance of RestTemplate
and make it @Spy
.
该RestTemplate
对象必须是一个真正的对象。如果您创建了一个真实的实例RestTemplate
并制作它,它应该可以工作@Spy
。
@Spy
private RestTemplate restTemplate = new RestTemplate();
回答by Debiprasad
If you are using RestTemplateBuilder
may be the usual thing wouldn't work. You need to add this in your test class along with when(condition).
如果您正在使用RestTemplateBuilder
可能是通常的事情行不通。您需要将它与 when(condition) 一起添加到您的测试类中。
@Before
public void setup() {
ReflectionTestUtils.setField(service, "restTemplate", restTemplate);
}
回答by Bhuwan Prasad Upadhyay
Let say you have an exchange call like below:
假设您有一个如下所示的交换电话:
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();
});
To mock this in your test case you can use mocitko as below:
要在您的测试用例中对此进行模拟,您可以使用 mocitko,如下所示:
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<AccountResponse>>any(),
ArgumentMatchers.<ParameterizedTypeReference<List<Object>>>any())
)