web-dev-qa-db-fra.com

Comment puis-je me moquer d'un REST échange de modèles?

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?

17
Akka Jaworek

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));
    }
17
Mindaugas
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);
14
Shyam Elakapalli

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

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);
4
Abbin Varghese

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

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();
0
Manoj Shrestha

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.

0
Dherik

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.

0
Kier GRAY