J'ai un service dans lequel je dois demander des informations à un serveur extérieur via 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();
}
}
Comment puis-je écrire un test JUnit pour getListofObjectsA()
?
J'ai essayé avec le dessous:
@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));
}
Cependant, le code ci-dessus ne fonctionne pas, il montre que responseEntitty
est null
. Comment puis-je corriger mon test pour simuler correctement restTemplate.exchange
?
Vous n'avez pas besoin de l'objet MockRestServiceServer
. L'annotation est @InjectMocks
pas @Inject
. Voici un exemple de code qui devrait fonctionner
@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));
}
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);
Ceci est un exemple avec le fichier// non argumenté ArgumentMatchers class
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<String>>any()))
.thenReturn(responseEntity);
Pour moi, je devais utiliser 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);
Ce travail de mon côté.
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);
L'instance RestTemplate
doit être un objet réel. Cela devrait fonctionner si vous créez une instance réelle de RestTemplate
et le faites @Spy
.
@Spy
private RestTemplate restTemplate = new RestTemplate();
Si votre intention est de tester le service sans vous soucier du reste de l'appel, je suggérerai de ne pas utiliser d'annotation dans votre test unitaire pour simplifier le test.
Ainsi, ma suggestion est refactor votre service pour recevoir le resttemplate en utilisant le constructeur d'injection. Cela facilitera le test. Exemple:
@Service
class SomeService {
@AutoWired
SomeService(TestTemplateObjects restTemplateObjects) {
this.restTemplateObjects = restTemplateObjects;
}
}
Le RestTemplate en tant que composant, à injecter et à simuler après:
@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;
}
}
Et le test:
public void test() {
when(mockedRestTemplateObject.get).thenReturn(mockRestTemplate);
//mock restTemplate.exchange
when(mockRestTemplate.exchange(...)).thenReturn(mockedResponseEntity);
SomeService someService = new SomeService(mockedRestTemplateObject);
someService.getListofObjectsA();
}
De cette manière, vous avez un accès direct pour simuler le modèle de repos par le constructeur SomeService.
J'ai implémenté une petite bibliothèque qui est très utile. Il fournit une ClientHttpRequestFactory
qui peut recevoir un certain contexte. Ce faisant, il permet de parcourir toutes les couches client telles que vérifier que les paramètres de requête sont valorisés, les en-têtes définis et que la désérialisation fonctionne bien.