web-dev-qa-db-fra.com

Comment utiliser mockito pour tester un REST un service?

Je suis très nouveau dans le test unitaire Java et j'ai entendu dire que le framework Mockito est vraiment bon pour les tests.

J'ai développé un serveur REST (méthodes CRUD) et je souhaite maintenant le tester, mais je ne sais pas comment?

Encore plus, je ne sais pas comment cette procédure de test devrait commencer. Mon serveur doit fonctionner sur localhost puis faire des appels sur cette URL (par exemple, localhost: 8888)?

Voici ce que j'ai essayé jusqu'à présent, mais je suis à peu près sûr que ce n'est pas la bonne façon.

    @Test
    public void testInitialize() {
        RESTfulGeneric rest = mock(RESTfulGeneric.class);

        ResponseBuilder builder = Response.status(Response.Status.OK);

        builder = Response.status(Response.Status.OK).entity(
                "Your schema was succesfully created!");

        when(rest.initialize(DatabaseSchema)).thenReturn(builder.build());

        String result = rest.initialize(DatabaseSchema).getEntity().toString();

        System.out.println("Here: " + result);

        assertEquals("Your schema was succesfully created!", result);

    }

Voici le code de la méthode initialize.

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/initialize")
    public Response initialize(String DatabaseSchema) {

        /** Set the LogLevel to Info, severe, warning and info will be written */
        LOGGER.setLevel(Level.INFO);

        ResponseBuilder builder = Response.status(Response.Status.OK);

        LOGGER.info("POST/initialize - Initialize the " + user.getUserEmail()
                + " namespace with a database schema.");

        /** Get a handle on the datastore itself */
        DatastoreService datastore = DatastoreServiceFactory
                .getDatastoreService();


        datastore.put(dbSchema);

        builder = Response.status(Response.Status.OK).entity(
                "Your schema was succesfully created!");
        /** Send response */
        return builder.build();
    }

Dans ce cas de test, je souhaite envoyer une chaîne Json au serveur (POST). Si tout se passe bien, le serveur doit répondre avec le message suivant: "Votre schéma a été créé avec succès!".

Quelqu'un peut-il m'aider s'il vous plaît?

24
Ion Morozan

D'ACCORD. Ainsi, le contrat de la méthode est le suivant: Analyser la chaîne d'entrée au format JSON et renvoyer BAD_REQUEST si elle est invalide. S'il est valide, créez une entité dans la datastore avec différentes propriétés (vous les connaissez) et renvoyez OK.

Et vous devez vérifier que ce contrat est rempli par la méthode. 

Où Mockito aide-t-il ici? Eh bien, si vous testez cette méthode sans Mockito, vous avez besoin d'une vraie DataStoreService et vous devez vérifier que l'entité a été créée correctement dans cette vraie DataStoreService. C’est là que votre test n’est plus un test unitaire, mais c’est aussi un endroit trop complexe à tester, trop long et trop difficile à exécuter car il nécessite un environnement complexe.

Mockito peut vous aider en vous moquant de la dépendance de DataStoreService: vous pouvez créer une maquette de DataStoreService et vérifier que cette maquette est bien appelée avec l'argument d'entité approprié lorsque vous appelez votre méthode initialize() dans votre test.

Pour ce faire, vous devez être capable d'injecter la DataStoreService dans votre objet testé. Cela peut être aussi simple que de refactoriser votre objet de la manière suivante:

public class MyRestService {
    private DataStoreService dataStoreService;

    // constructor used on the server
    public MyRestService() {
        this.dataStoreService = DatastoreServiceFactory.getDatastoreService();
    }

    // constructor used by the unit tests
    public MyRestService(DataStoreService dataStoreService) {
        this.dataStoreService = dataStoreService;
    }

    public Response initialize(String DatabaseSchema) {
         ...
         // use this.dataStoreService instead of datastore
    }
}

Et maintenant, dans votre méthode de test, vous pouvez faire:

@Test
public void testInitializeWithGoodInput() {
    DataStoreService mockDataStoreService = mock(DataStoreService.class);
    MyRestService service = new MyRestService(mockDataStoreService);
    String goodInput = "...";
    Response response = service.initialize(goodInput);
    assertEquals(Response.Status.OK, response.getStatus());

    ArgumentCaptor<Entity> argument = ArgumentCaptor.forClass(Entity.class);
    verify(mock).put(argument.capture());
    assertEquals("the correct kind", argument.getValue().getKind());
    // ... other assertions
}
23
JB Nizet

Ce dont vous parlez ressemble plus à aux tests d’intégration et Mockito (ou tout autre framework moqueur) ne vous sera pas très utile.

Si vous voulez écrire le code de test unitaire que vous avez écrit, Mockito est certainement un outil utile.

Je vous suggère de lire davantage sur le moquage/les tests unitaires et sur les circonstances dans lesquelles il devrait être utilisé.

3
darrengorman

Mockito est (généralement) pour tester des portions de code; Par exemple, si vous utilisiez votre service REST sans vouloir effectuer un test de pile complète, vous simuleriez le service connecté au service REST, ce qui vous permettait de le faire précisément. systématiquement, testez le comportement spécifique.

Pour tester des parties internes du service REST (par exemple, une méthode de service spécifique) sans toucher une base de données, vous devez simuler le sous-système de la base de données, permettant ainsi de tester uniquement les internes du service, sans impliquer la base de données. Ce test appartient au module de service REST, pas au côté client.

Pour tester le service REST lui-même, vous utiliseriez une bibliothèque client réelle, créant ainsi un test d'intégration full-stack. Mockito pourrait être utilisé ici pour simuler des parties du client non liées à la consommation de service REST.

2
Dave Newton

La meilleure méthode consiste à utiliser wiremock Ajouter les dépendances suivantes: com.github.tomakehurst wiremock 2.4.1 org.igniterealtime.smack smack-core 4.0.6

Définissez et utilisez le câble comme indiqué ci-dessous

@Rule
public WireMockRule wireMockRule = new WireMockRule(8089);

String response ="Hello world";
StubMapping responseValid = stubFor(get(urlEqualTo(url)).withHeader("Content-Type", equalTo("application/json"))
        .willReturn(aResponse().withStatus(200)
                .withHeader("Content-Type", "application/json").withBody(response)));
1
Yallaling Goudar

Je conviens que ce n'est pas un test unitaire, mais un test d'intégration. Quoi qu'il en soit, vous préférez jeter un coup d'œil aux tests du serveur et du serveur grizzly intégré. Pour résumer, ce code démarre le serveur grizzly (qui pourrait également démarrer la base de données) sur localhost: 8888, puis configure le client du maillot du client et envoie une demande POST dont la réponse doit être testée. Ceci est une intégration puisque vous testez le serveur et la base de données, vous pouvez utiliser mockito pour émuler la base de données, mais cela dépend de la relation entre votre serveur et votre base de données.

(test avec le maillot 1.11 et le grizzly 2.2)

    @BeforeClass
    public static void setUpClass() throws Exception {
        // starts grizzly
        Starter.start_grizzly(true);
        Thread.sleep(4000);
    }

    @Before
    public void setUp() throws Exception {
        client = new Client();
        webResource = client.resource("http://localhost:8888");
    }   

    @Test
    public void testPostSchemaDatabase() throws Exception {
        {
            String DatabaseSchema = "{ database_schema : {...}}";
            logger.info("REST client configured to send: "  + DatabaseSchema);
            ClientResponse response =  
                    webResource
                             .path("/initialize")
                             .type("application/json")
                             .post(ClientResponse.class, DatabaseSchema);
            //wait for the server to process
            Thread.sleep(2000);
            assertEquals(response.getStatus(), 204);    
            //test the response
        }       
    }

    @After
    public void after() throws JSONException
    {
            //probably you want to delete the schema at database and stop the server

}
0
user311174