Comment utiliser mockito pour tester un service REST?

Je suis très nouveau dans les tests unitaires Java et j'ai entendu dire que le framework Mockito est vraiment bon à des fins de test.

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

Encore plus, Je ne sais pas comment cette procédure de test devrait commencer. Mon serveur devrait fonctionner sur localhost et ensuite faire des appels sur cette url (par exemple localhost:8888)?

Voici ce que j'ai essayé jusqu'à présent, mais je suis sûr que ce n'est pas le bon 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 veux envoyer une chaîne Json au serveur (POST). Si tout s'est bien passé, le serveur devrait répondre par " votre schéma a été créé avec succès!".

Quelqu'un Peut-il m'aider?

23
demandé sur Ion Morozan 2012-05-27 19:48:57

5 réponses

OK. Ainsi, le contrat de la méthode est le suivant: analyser la chaîne d'entrée en tant que JSON, et renvoyer BAD_REQUEST si elle est invalide. Si elle est valide, créez une entité dans le datastore avec diverses 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'un réel DataStoreService, et vous devez vérifier que l'entité a été créée correctement dans ce réel DataStoreService. C'est là que votre test n'est plus un test unitaire, et c'est aussi là qu'il est trop complexe à tester, trop long et trop difficile à exécuter car il a besoin d'un environnement complexe.

Mockito peut aider en se moquant de la dépendance sur le DataStoreService: vous pouvez créer un simulacre de DataStoreService, et vérifier que ce simulacre est bien appelé avec l'argument entity approprié lorsque vous appelez votre méthode initialize() dans votre test.

Pour ce faire, vous devez pouvoir injecter le DataStoreService dans votre objet sous test. Cela peut être aussi simple que de refactorer 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
}
21
répondu JB Nizet 2018-01-12 20:37:49

Ce dont vous parlez ressemble plus à les tests d'intégration et Mockito (ou tout autre framework moqueur) ne vous seront pas d'une grande utilité.

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

Je vous suggère de lire plus sur les tests moqueurs/unitaires et dans quelles circonstances il devrait être utilisé.

3
répondu darrengorman 2012-05-27 15:58:08

Mockito est (généralement) pour tester portions de code; par exemple, si vous consommez votre service REST, mais ne voulez pas faire un test de pile complète, vous vous moqueriez du service connecté au service REST, vous permettant de tester avec précision et cohérence un comportement spécifique.

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

Pour tester le service REST lui-même, vous utiliserez une bibliothèque client réelle, créant un test d'intégration de pile complète. Mockito pourrait être utilisé ici pour simuler des portions du client sans rapport avec la consommation du service REST.

2
répondu Dave Newton 2012-05-27 16:03:44

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 wiremock 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
répondu Yallaling Goudar 2016-12-07 13:39:44

Je suis d'accord que ce n'est pas un test unitaire mais un test d'intégration, de toute façon vous préférez jeter un oeil aux tests jersey et grizzly Server intégrés. Pour résumer, ce code démarre le serveur grizzly (qui pourrait également démarrer la base de données) à localhost: 8888, puis configure le client jersey du client et envoie une requête POST dont la réponse doit être testée. Ceci est une intégration puisque vous testez à la fois 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 façon dont votre serveur de base de données et sont.

(test avec jersey 1.11 et 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
répondu user311174 2012-05-28 06:42:07