Mocking a RestTemplate in Spring

1. Introduzione

Spesso ci troviamo con applicazioni che eseguono una sorta di richiesta web. Quando si tratta di testare questo comportamento, abbiamo alcune opzioni con le app Spring.

In questo breve tutorial, vedremo solo un paio di modi per deridere tali chiamate eseguite solo tramite RestTemplate .

Inizieremo i test con Mockito, una popolare libreria di scherno. Quindi, utilizzeremo Spring Test che ci fornisce un meccanismo per creare un server fittizio per definire le interazioni del server.

2. Utilizzo di Mockito

Potremmo usare Mockito per deridere del tutto RestTemplate . Con questo approccio, testare il nostro servizio sarebbe semplice come qualsiasi altro test che implichi la presa in giro.

Supponiamo di avere una semplice classe EmployeeService , che recupera i dettagli dei dipendenti tramite HTTP:

@Service public class EmployeeService { @Autowired private RestTemplate restTemplate; public Employee getEmployee(String id) { ResponseEntity resp = restTemplate.getForEntity("//localhost:8080/employee/" + id, Employee.class); return resp.getStatusCode() == HttpStatus.OK ? resp.getBody() : null; } } 

Implementiamo il nostro test per il codice precedente:

@RunWith(MockitoJUnitRunner.class) public class EmployeeServiceTest { @Mock private RestTemplate restTemplate; @InjectMocks private EmployeeService empService = new EmployeeService(); @Test public void givenMockingIsDoneByMockito_whenGetIsCalled_shouldReturnMockedObject() { Employee emp = new Employee(“E001”, "Eric Simmons"); Mockito .when(restTemplate.getForEntity( “//localhost:8080/employee/E001”, Employee.class)) .thenReturn(new ResponseEntity(emp, HttpStatus.OK)); Employee employee = empService.getEmployee(id); Assert.assertEquals(emp, employee); } }

Nella classe di test JUnit sopra, abbiamo prima chiesto a Mockito di creare un'istanza fittizia RestTemplate utilizzando l' annotazione @Mock .

Quindi, abbiamo annotato l' istanza EmployeeService con @InjectMocks per iniettarvi l'istanza fittizia.

Infine, nel metodo di test, abbiamo definito il comportamento del nostro mock utilizzando il supporto di Mockito quando / poi.

3. Utilizzo del test di primavera

IlIl modulo Spring Test include un server fittizio denominato MockRestServiceServer. Con questo approccio, configuriamo il server per restituire un oggetto particolare quando una richiesta specifica viene inviata tramite la nostra istanza RestTemplate . Infine, possiamo verificare () su quell'istanza del server se tutte le aspettative sono state soddisfatte o meno.

MockRestServiceServer funziona effettivamente intercettando le chiamate API HTTP utilizzando un MockClientHttpRequestFactory . In base alla nostra configurazione, crea un elenco di richieste attese e risposte corrispondenti. Quando l' istanza RestTemplate chiama l'API, cerca la richiesta nel suo elenco di aspettative e restituisce la risposta corrispondente.

Pertanto, elimina la necessità di eseguire un server HTTP in qualsiasi altra porta per inviare risposte fittizie.

Creiamo un semplice test per lo stesso esempio getEmployee () utilizzando MockRestServiceServer :

@RunWith(SpringRunner.class) @ContextConfiguration(classes = SpringTestConfig.class) public class EmployeeServiceMockRestServiceServerUnitTest { @Autowired private EmployeeService empService; @Autowired private RestTemplate restTemplate; private MockRestServiceServer mockServer; private ObjectMapper mapper = new ObjectMapper(); @Before public void init() { mockServer = MockRestServiceServer.createServer(restTemplate); } @Test public void givenMockingIsDoneByMockRestServiceServer_whenGetIsCalled_thenReturnsMockedObject()() { Employee emp = new Employee("E001", "Eric Simmons"); mockServer.expect(ExpectedCount.once(), requestTo(new URI("//localhost:8080/employee/E001"))) .andExpect(method(HttpMethod.GET)) .andRespond(withStatus(HttpStatus.OK) .contentType(MediaType.APPLICATION_JSON) .body(mapper.writeValueAsString(emp)) ); Employee employee = empService.getEmployee(id); mockServer.verify(); Assert.assertEquals(emp, employee); } } 

Nello snippet precedente, abbiamo utilizzato metodi statici da MockRestRequestMatchers e MockRestResponseCreators per definire l'aspettativa e la risposta per la chiamata REST in modo chiaro e leggibile:

import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; import static org.springframework.test.web.client.response.MockRestResponseCreators.*;

Dobbiamo tenere presente che RestTemplate nella classe di test dovrebbe essere la stessa istanza utilizzata nella classe EmployeeService . Per garantire ciò, abbiamo definito un bean RestTemplate nella configurazione di primavera e abbiamo cablato automaticamente l'istanza sia nel test che nell'implementazione:

@Bean public RestTemplate restTemplate() { return new RestTemplate(); }

L'utilizzo di un MockRestServiceServer è molto utile quando scriviamo i nostri test di integrazione e dobbiamo solo simulare le chiamate HTTP esterne.

4. Conclusione

In questo breve articolo, abbiamo discusso alcune opzioni efficaci per deridere le chiamate API REST esterne su HTTP durante la scrittura di unit test.

Il codice sorgente per l'articolo precedente è disponibile su GitHub.