REST 템플릿 교환을 모의하려면 어떻게 해야 하나요?
외부 서버에 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?
필요없습니다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));
}
이것은 권장되지 않는ArgumentMatchers 클래스의 예입니다.
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
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);
저는 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);
이건 내 편이야.
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);
그RestTemplate인스턴스는 실제 객체여야 합니다.의 실제 인스턴스를 작성하면 동작합니다.RestTemplate만들어 내다@Spy.
@Spy
private RestTemplate restTemplate = new RestTemplate();
나는 그런 실수를 하곤 했다.나는 더 신뢰할 수 있는 해결책을 찾았다.수입 명세서도 말씀드렸는데, 저에게도 효과가 있었습니다.다음 코드 조각은 시스템 플레이트를 완벽하게 모킹합니다.
import org.syslogito 를 지정합니다.매처
import static org.syslogito.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);
restTemplate를 조롱하는 동안 이 문제가 발생한 경우.교환(...) 문제인 것 같습니다.예를 들어, 다음이 작동하지 않습니다.
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));
모키토에 주목하세요.두 번째 블록의 anyString()과 Mockito.any()를 비교합니다.
다음과 같은 교환 전화가 있다고 가정해 보겠습니다.
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())
)
restTemplate를 사용하여 외부 시스템과 통신하는 클라이언트를 테스트하는 경우 유닛 테스트의 일부로 송신하는httpEntity, 헤더 및 파라미터를 확인해야 합니다.
이러한 상황에서는 Argument Captor가 유용합니다.예를 들어 다음과 같습니다(작업 코드).
@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")
이제 전송된 캡처된 개체를 받았기 때문에 사용 사례에 따라 어설션을 수행할 수 있습니다.
아래 권장되지 않는 ArgumentMatchers를 사용할 수 있습니다.
lenient().when(restTemplate.exchange(ArgumentMatchers.any(String.class),
ArgumentMatchers.eq(HttpMethod.GET),
ArgumentMatchers.any(),
ArgumentMatchers.eq(new ParameterizedTypeReference<List<ObjectA>>() {
})))
.thenReturn(responseEntity);
나는 꽤 유용한 작은 도서관을 구현했다.이 기능을 통해ClientHttpRequestFactory콘텍스트를 수신할 수 있습니다.이를 통해 쿼리 파라미터가 평가되고 있는지, 헤더가 설정되어 있는지, 역직렬화가 정상적으로 동작하는지 등의 모든 클라이언트레이어를 확인할 수 있습니다.
사용하시는 경우RestTemplateBuilder통상의 일이 아닐 수도 있어요이것을 시험 시간에 언제와 함께 추가해야 합니다.
@Before
public void setup() {
ReflectionTestUtils.setField(service, "restTemplate", restTemplate);
}
아직 이 문제를 겪고 있는 사람이 있다면 캡터 주석이 도움이 되었습니다.
@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);
이 특정 exchange()의 경우 stub 대신 stub으로 하는 것이 더 쉽다는 것을 알게 되었습니다.good old override:
var restTemplate = new RestTemplate() {
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
}
};
모조품을 줄이다특히 api는 항상 변경됩니다.eq(..) any()..기타.
stubbed exchange() 내의 arg를 체크한 후 반환하거나 예외를 발생시킬 수 있습니다.
그것이 그 엄격한 질문에 대한 답이 아니라는 것을 알고 있다.하지만 결과는 똑같다.코드도 적고 지원도 간단합니다.
mockito-core-2.23.4 탑재
ResponseEntity<YOUR_CLASS> responseEntity = new ResponseEntity(YOUR_CLASS_OBJECT, HttpStatus.OK);
when(restTemplate.exchange(Mockito.anyString(), Mockito.any(), Mockito.any(), Mockito.<ParameterizedTypeReference<YOUR_CLASS>> any()))
.thenReturn(responseEntity);
- 이런 식으로 하는 거였어 - 모키토when(restTemplate).(URI) any() 、 ( HttpMethod ) any() 、 ( HttpEntity < ) 。>) any() , (Class) any() ).그러면 Return(responseEntity);
그러나 위의 코드는 작동하지 않습니다.responseEntitty가 null임을 나타냅니다.restTemplate를 적절하게 모킹하도록 테스트를 수정하려면 어떻게 해야 합니까?교환할 수 있습니까?
다음을 사용하여 null을 반환합니다.
@Mock
private RestTemplate restTemplate;
그 목적이 조롱하는 것이라면MockRestServiceServerMockito을 사용하다
@Autowired
private RestTemplate restTemplate;
★★★★★★★★★★★★★★★★★」RestTemplate restTemplate = new RestTemplate()가 ""에 MockRestServiceServer ★★★★★★★★★★★★★★★★★」SomeService.
예를 들어 다음과 같습니다.
@Test
public void methodWithPostCallTest() throws URISyntaxException {
RestTemplate restTemplate = new RestTemplate();
MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
mockServer.expect(ExpectedCount.once(),
requestTo(new URI("post-method-url")))
.andExpect(method(HttpMethod.POST))
.andRespond(withStatus(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON)
.body("response-body")
);
YourService yourService = new YourService(restTemplate);
String response = yourService.methodWhichExecutesPostCall();
mockServer.verify();
assertEquals("response-body", response);
}
「」를 사용합니다.MockRestServiceServer의 RestTemplate 메서드에 대한 모의 응답을 반환합니다.POST- - -postForEntity,postForObject ★★★★★★★★★★★★★★★★★」exchange.
만약 당신이 나머지 통화에 신경 쓰지 않고 서비스를 테스트하고자 한다면, 나는 테스트를 간소화하기 위해 유닛 테스트에 주석을 사용하지 말 것을 제안합니다.
그래서 제가 제안하는 것은 주입 컨스트럭터를 사용하여 rest template를 받을 수 있도록 당신의 서비스를 리팩터링하는 것입니다.이렇게 하면 테스트가 쉬워집니다.예:
@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();
}
이렇게 하면 Some Service 컨스트럭터가 나머지 템플릿을 직접 시뮬레이션할 수 있습니다.
언급URL : https://stackoverflow.com/questions/39486521/how-do-i-mock-a-rest-template-exchange
'source' 카테고리의 다른 글
| 각도에서의 스코프 문제각도 사용 JSUI 부트스트랩모달 (0) | 2023.02.12 |
|---|---|
| 이 단순한 문자열은 유효한 JSON으로 간주됩니까? (0) | 2023.02.12 |
| Angularjs 크롬 자동 완성 딜레마 (0) | 2023.02.12 |
| react-router v4에서 history.push/Link/Redirect를 포함한 파라미터를 전달하려면 어떻게 해야 합니까? (0) | 2023.02.12 |
| C#을 Oracle 데이터베이스에 연결하기 위해 필요한 최소 클라이언트 설치 공간은 얼마입니까? (0) | 2023.02.12 |