1
votes

Comment écrire des cas de test Mockito Junit pour le modèle Rest?

Depuis le service, j'appelle l'API tierce en utilisant RestTemplate.

@Component
public class ForceService {
    private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,  RestTemplate restTemplate) {
    this.config = config;
    this.restTemplate = restTemplate;
}
public String createLead(Lead lead) {
    HttpHeaders headers = new HttpHeaders();
    headers.set(AUTHORIZATION, getAccessToken());
    headers.set(ACCEPT, APPLICATION_JSON);
    headers.set(CONTENT_TYPE, APPLICATION_JSON);
    LeadWrap leadWrap = new LeadWrap();
    leadWrap.setFirstName(lead.getFirstName());
    leadWrap.setLastName(lead.getLastName());
    leadWrap.setEmail(lead.getEmail());
    leadWrap.setPhone(lead.getPhone());

    String jsonString;
    try {
        jsonString = new ObjectMapper().writeValueAsString(leadWrap);

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    HttpEntity<String> entity = new HttpEntity<>(jsonString, headers);

    ResponseEntity<CreateRecordResult> exchange = restTemplate.exchange(
            config.restUrl + "/v" + config.restVersion + "/sobjects/Lead/", HttpMethod.POST, entity,
            CreateRecordResult.class);
    if (exchange.getStatusCode().equals(HttpStatus.CREATED)) {
        if (exchange.getBody() != null && exchange.getBody().success) {
            LOGGER.info("Lead record created with Id " + exchange.getBody().id);
            return exchange.getBody().id;
        }
        throw new RuntimeException("Record is not created");
    } else {
        LOGGER.error(RETURN_STATUS + exchange.getStatusCode());
        throw new RuntimeException(RETURN_STATUS + exchange.getStatusCode());
    }

J'ai essayé d'utiliser à la fois la méthode any () et de spécifier directement les valeurs. Spécifier directement la valeur dans entity ne semble pas être la bonne façon de tester. Voici la classe de service pour laquelle j'ai besoin d'écrire des cas de test.

@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
@InjectMocks
private ForceService forceService;
@Mock
private RestTemplate restTemplate;
@Before
public void setup() {
    forceService = new ForceService(config, restTemplate);
}
@Test
public void createTest_valid() throws JSONException {
    /*Mockito.when(restTemplate.exchange(url, HttpMethod.POST, entity, CreateRecordResult.class))
    .thenReturn(response);*/
     Mockito.verify(restTemplate, Mockito.times(1))
    .exchange(Mockito.anyString(),
                    Mockito.<HttpMethod> any(),
                    Mockito.<HttpEntity<?>> any(),
                    Mockito.<Class<?>> any());
    forceService.createLead(lead);
}
}

Le cas de test ci-dessus renvoie l'échange ResponseEntity comme nul. Existe-t-il une solution pour que le scénario de test fonctionne pour l'appel d'échange RestTemplate?


0 commentaires

3 Réponses :


0
votes

Vous devez dire à Mockito ce qu'il doit renvoyer lorsque le simulacre est appelé ...

when(restTemplate.exchange(anyString(), any(), any(), any())).thenReturn(...

Insérez l'entité de réponse que vous voulez renvoyer de l'appel à échanger dans le thenReturn.


2 commentaires

J'ai créé la réponse et j'ai réussi aussi, mais cela n'a pas fonctionné. En outre, ResponseEntity response = new ResponseEntity <> (résultat, HttpStatus.CREATED); Mockito.when (restTemplate.exchange (anyString (), any (), any (), any ())) .thenReturn (réponse); renvoie l'erreur "La méthode d'échange (String, HttpMethod, HttpEntity , Class , Object []) est ambiguë pour le type RestTemplate"


Pouvez-vous mettre à jour le code de votre message avec la modification et l'erreur que vous obtenez?



0
votes

La vérification doit aller après l'appel au code de production, dans votre cas l'appel createLead () . Vous allez également vouloir utiliser des matchers pour votre appel, qui ne devraient probablement pas être commentés. Dans des cas comme le vôtre, vous n'avez généralement pas besoin à la fois du moment et de la vérification. Cela rend simplement le test plus complexe et plus difficile à lire.

J'utilise la vérification s'il n'y a pas de retour de l'appel de service sur lequel je peux affirmer. Dans ces cas, j'emballerais tous les paramètres du when (si nécessaire pour dépasser une exception de pointeur nul ou une autre erreur) dans any () tel que any (HttpEntity.class) ou anyString () donc les paramètres ne sont pas ambigus. Ensuite, vous pouvez utiliser la vérification pour confirmer que les paramètres réels sont corrects. Cette stratégie est plus facile à maintenir. Malheureusement, il faut souvent un capteur d'arguments pour vérifier que les en-têtes ou autres paramètres sont envoyés correctement. Je dis que c'est malheureux parce que les tests deviennent gros et compliqués,

Si je peux affirmer sur le résultat, j'utilise souvent juste le quand. Dans ce cas, j'envelopperais les paramètres avec eq () , comme eq (httpEntity) . Dans ce cas, la classe HttpEntity aurait besoin d'une bonne méthode .equals () ou elle utiliserait simplement la valeur par défaut et n'est probablement pas très utile. Mais, il est généralement assez puissant.

Vous ne devez pas utiliser @InjectMocks et initialiser dans la configuration. Si vous @InjectMocks , il crée l'instance et injecte les simulacres. Vous semblez vouloir mettre une vraie configuration afin que vous utilisiez la méthode de configuration ou vous pourriez vous moquer de la configuration. J'ai utilisé un matcher correct, mais vous devrez peut-être les affiner, par exemple changer certains any () en eq () pour vraiment tester ce que vous voulez tester. J'ai également réorganisé pour que l'action ou l'appel à la production soit avant la vérification. Ce test devrait vous aider à démarrer.

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {

    private ForceService forceService;
    @Mock
    private RestTemplate restTemplate;

    @Before
    public void setup() {
        forceService = new ForceService(new ForceServiceConfig(), restTemplate);
    }

    @Test
    public void createTest_valid() throws Exception {
        when(restTemplate.exchange(anyString(), eq(HttpMethod.POST),
                any(HttpEntity.class),
                eq(CreateRecordResult.class)))
                .thenReturn(new ResponseEntity<>(new CreateRecordResult(), HttpStatus.CREATED));

        forceService.createLead();

        verify(restTemplate, times(1))
                .exchange(eq("config.restUrl/vconfig.restVersion/sobjects/Lead/"),
                        any(HttpMethod.class),
                        any(HttpEntity.class),
                        eq(CreateRecordResult.class));
    }
}


2 commentaires

Mockito.when (restTemplate.exchange (Matchers.eq (url), Matchers.eq (HttpMethod.POST), Matchers. > any (), Matchers. > any‌ ())) .thenReturn (réponse); J'ai essayé cela aussi, mais cela n'a pas fonctionné. Il retourne à nouveau null.


@Sowmeashree a écrit un exemple qui utilise votre code.



0
votes

Le code @DCTID m'a sauvé la journée. Parallèlement à cela, j'ai rencontré le problème ci-dessous et je l'ai résolu. Pour se moquer du corps de ResponseEntity, j'ai créé un objet et lui ai défini une valeur. Sinon, il ne passait pas cette condition - if (exchange.getBody ()! = Null && exchange.getBody (). Success)

CreateRecordResult createRecordResult = new CreateRecordResult();
createRecordResult.success = true;
Mockito.when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class),
            eq(CreateRecordResult.class)))
                    .thenReturn(new ResponseEntity<>(createRecordResult, HttpStatus.CREATED));


0 commentaires