Как мне высмеять обмен шаблонами REST?
У меня есть служба, в которой мне нужно запросить внешний сервер через отдых для получения некоторой информации:
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();
}
}
Как я могу написать тест JUnit для getListofObjectsA()
?
Я попробовал следующее:
@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
?
Ответы
Ответ 1
Вам не нужен объект 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));
}
Ответ 2
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);
Ответ 3
Это пример с неотменяемым классом ArgumentMatchers
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
Ответ 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);
Ответ 5
Эта работа на моей стороне.
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);
Ответ 6
Я внедрил небольшую библиотеку, которая весьма полезна. Он предоставляет ClientHttpRequestFactory
, который может получить некоторый контекст. Таким образом, он позволяет проходить через все клиентские уровни, такие как проверка того, что параметры запроса оцениваются, набор заголовков и проверка того, что десериализация работает хорошо.
Ответ 7
Если ваше намерение является тестированием службы без забот о остальном вызове, я предлагаю не использовать аннотацию в unit test для упрощения теста.
Итак, мое предложение реорганизует вашу службу для получения resttemplate с использованием конструктора инъекций. Это облегчит испытание. Пример:
@Service
class SomeService {
@AutoWired
SomeService(TestTemplateObjects restTemplateObjects) {
this.restTemplateObjects = restTemplateObjects;
}
}
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;
}
}
И тест:
public void test() {
when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate);
//mock restTemplate.exchange
when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity);
SomeService someService = new SomeService(mockedRestTemplateObject);
someService.getListofObjectsA();
}
Таким образом, у вас есть прямой доступ к шаблону останова с помощью конструктора SomeService.
Ответ 8
Экземпляр RestTemplate
должен быть реальным объектом. Это должно работать, если вы создаете реальный экземпляр RestTemplate
и делаете его @Spy
.
@Spy
private RestTemplate restTemplate = new RestTemplate();
Ответ 9
Если вы используете RestTemplateBuilder
может быть, обычная вещь не будет работать. Вы должны добавить это в свой тестовый класс вместе с when (условие).
@Before
public void setup() {
ReflectionTestUtils.setField(service, "restTemplate", restTemplate);
}