unit test example baeldung java spring-boot junit mockito

java - test - ¿Cómo me burlo de un intercambio de plantillas REST?



spring test (8)

Tengo un servicio en el que necesito pedir información a un servidor externo a través del resto:

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(); } }

¿Cómo puedo escribir una prueba JUnit para getListofObjectsA() ?

He intentado con el siguiente:

@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)); }

Sin embargo, el código anterior no funciona, muestra que responseEntitty es null . ¿Cómo puedo corregir mi prueba para restTemplate.exchange correctamente restTemplate.exchange ?


Este es un ejemplo con la clase ArgumentMatchers no abatida

when(restTemplate.exchange( ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), ArgumentMatchers.<Class<String>>any())) .thenReturn(responseEntity);


Este trabajo por mi parte.

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);


Implementé una pequeña biblioteca que es bastante útil. Proporciona un ClientHttpRequestFactory que puede recibir algún contexto. Al hacerlo, permite pasar por todas las capas del cliente, como verificar que los parámetros de consulta estén valorados, establecer los encabezados y verificar que la deserialización funcione bien.


La instancia de RestTemplate tiene que ser un objeto real. Debería funcionar si creas una instancia real de RestTemplate y la haces @Spy .

@Spy private RestTemplate restTemplate = new RestTemplate();


No necesitas el objeto MockRestServiceServer . La anotación es @InjectMocks no @Inject . A continuación se muestra un código de ejemplo que debería funcionar

@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)); }


Para mí, tuve que usar 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);


Si su intención es probar el servicio sin preocuparse por la llamada de descanso, sugeriré que no use ninguna anotación en su prueba de unidad para simplificar la prueba.

Por lo tanto, mi sugerencia es refactorizar su servicio para recibir la placa de descanso utilizando el constructor de inyección. Esto facilitará la prueba. Ejemplo:

@Service class SomeService { @AutoWired SomeService(TestTemplateObjects restTemplateObjects) { this.restTemplateObjects = restTemplateObjects; } }

El RestTemplate como componente, para ser inyectado y burlado después de:

@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; } }

Y la prueba:

public void test() { when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate); //mock restTemplate.exchange when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity); SomeService someService = new SomeService(mockedRestTemplateObject); someService.getListofObjectsA(); }

De esta manera, tiene acceso directo para simular el resto de la plantilla mediante el constructor SomeService.


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);