Ion Morozan Ion Morozan - 8 days ago 7
Java Question

How to use mockito for testing a REST service?

I am very new in Java Unit Testing and I heard that Mockito framework is really good for testing purposes.

I have developed a REST Server (CRUD methods) and now I want to test it, but I don't know how?

Even more I don't know how this testing procedure should begin. My server should work on localhost and then make calls on that url(e.g. localhost:8888)?

Here is what I tried so far, but I'm pretty sure that this isn't the right way.

@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);

}


Here is the code for
initialize
method.

@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();
}


In this test case I want to send a Json string to the server(POST). If everything went well then the server should reply with "Your schema was succesfully created!".

Can someone please help me?

Answer

OK. So, the contract of the method is the following: Parse the input string as JSON, and send back BAD_REQUEST if it's invalid. If it's valid, create an entity in the datastore with various properties (you know them), and send back OK.

And you need to verify that this contract is fulfilled by the method.

Where does mockito help here? Well, if you test this method without Mockito, you need a real DataStoreService, and you need to verify that the entity has been created correctly in this real DataStoreService. This is where your test is not a unit test anymore, and this is also where it's too complex to test, too long, and too hard to run because it needs a complex environment.

Mockito can help by mocking the dependency on the DataStoreService: you can create a mock DataStoreService, and verify that this mock is indeed called with the appropriate entity argument when you call your initialize() method in your test.

To do that, you need to be able to inject the DataStoreService into your object under test. It can be as easy as refactoring your object in the following way:

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
    }
}

And now in your test method, you can do:

@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
}