Hot questions for Using Mockito in jersey

Question:

I've run into a strange issue with unit testing the following jersey client call:

WebResource webResource = _client.resource(url);
ClientResponse response = webResource
                        .accept("application/json")
                        .type("application/x-www-form-urlencoded")
                        .post(ClientResponse.class, postBody);

PostBody is a MultivaluedMap.

The unit test verifies fine the accept and type calls but fails on the post one with this exception:

org.mockito.exceptions.misusing.NullInsteadOfMockException: 
Argument passed to verify() should be a mock but is null!

Here's the test code:

_client = Mockito.mock(Client.class);
        _webResource = Mockito.mock(WebResource.class);
        _builder = Mockito.mock(WebResource.Builder.class);
        _response = Mockito.mock(ClientResponse.class);

        Mockito.when(_client.resource(Mockito.anyString())).thenReturn(_webResource);

        Mockito.when(_response.getEntity(Mockito.any(Class.class))).thenReturn(new RefreshTokenDto());
        Mockito.when(_response.getStatus()).thenReturn(200);

        Mockito.when(_builder.post(Mockito.eq(ClientResponse.class), Mockito.anyObject())).thenReturn(_response);
        Mockito.when(_builder.type(Mockito.anyString())).thenReturn(_builder);
        Mockito.when(_webResource.accept(Mockito.anyString())).thenReturn(_builder);

        RefreshTokenDto response = _clientWrapper.exchangeAuthorizationCodeForToken(_token);

        Assert.assertNotNull(response);

        Mockito.verify(_client.resource(_baseUrl + "token"));
        Mockito.verify(_webResource.accept("application/json"));
        Mockito.verify(_builder.type("application/x-www-form-urlencoded"));

        // TODO: this line throws NullRefExc for some unknown reason
        Mockito.verify(_builder.post(Mockito.any(Class.class), Mockito.any(MultivaluedMap.class)));

Can you see anything wrong with this code?


Answer:

Yes. You've misused verify. The argument to verify has to be the mock itself. Then you call the method you want to verify on the value that's returned by verify. So in this case, the first verify call should be

Mockito.verify(_client).resource(_baseUrl + "token");

and similarly for the other verify calls.

Question:

I am having a play with testing a RESTful api which I have set up using Jersey. I want to test it using JUnit while running it with Grizzly to provide the Http container.

General testing using the server works ok, i.e. sending requests and receiving responses etc.

The api is called CMSApi and it has a dependency called skyService which I would like to mock out so I'm testing just the api. So the question is how can I inject the CMSApi with a mockSkyService object created using Mockito? The relevant code is below:

Grizzly Server start up:

public static HttpServer startServer() {
    final ResourceConfig rc = new ResourceConfig().packages("com.sky");
    rc.property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
    return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);

}

My JUnit calls the above start method:

@Before
public void setUpServer() throws Exception {

    // start the server and create the client
    server = Main.startServer();

    Client client = ClientBuilder.newClient();
    target = client.target(Main.BASE_URI);
}

I run the test using the @RunWith(MockitoJUnitRunner.class).

Here are the relevant objects in the test:

//System Under Test
private CMSApi cmsApi;

//Mock
@Mock private static SkyService mockSkyService;

Here is the test method calling:

  @Test
public void testSaveTile() {

    //given
    final Invocation.Builder invocationBuilder = target.path(PATH_TILE).request(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);

    Tile tile = new Tile(8, "LABEL", clientId, new Date(), null);

    //when      
    Response response = invocationBuilder.post(Entity.entity(tile, MediaType.APPLICATION_JSON_TYPE));

    //then
    assertEquals(Status.OK.getStatusCode(), response.getStatus());

}

Maven dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.sky</groupId>
<artifactId>sky-service</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>sky-service</name>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

 <dependencies>
     <dependency> 
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        </dependency>        
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-bundle</artifactId>
        <type>pom</type>
        <scope>test</scope>

    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-bean-validation</artifactId>
        </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.16</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
        <scope>test</scope>
    </dependency>
    <!-- Dependency for Mockito -->
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-all</artifactId>
        <version>1.9.5</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <inherited>true</inherited>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.sky.Main</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

<properties>
    <jersey.version>2.15</jersey.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


Answer:

You're going to need to tap into the ResourceConfig, as you will need to explicitly register the CMSApi, so that you can inject it with the mocked SkyService prior to registering. It would basically look something like

// Sample interface
public interface SkyService {
    public String getMessage();
}

@Path("...")
public class CMSApi {
    private SkyService service;
    public void setSkyService( SkyService service ) { this.service = service; }
}

// Somewhere in test code
CMSApi api = new CMSApi();
SkyServicer service = Mockito.mock(SkyService.class);
Mockito.when(server.getMessage()).thenReturn("Hello World");
api.setSkyService(service);
resourceConfig.register(api);

The key is to have your resource class set up for injection of its dependency. Easier testing is one of the benefits of dependency injection. You can inject through constructor, or through a setter as I have done, or through an injection framework with the @Inject annotation.

You can see a more complete example here, which uses the Jersey DI framework HK2. You can also see more about Jersey and HK2 here. Then example also uses the Jersey Test Framework, which I see you already have as a dependency, so you might want to leverage that. Here is another example which uses Jersey 1, but the concept is the same, and you might be able to get some ideas from it.

As an aside, it looks like you're using the Jersey archetype, which I am familiar with. So the code for the config you are showing is in a different class. You may not want to mess with the current app configuration, so maybe your best bet is to use the test framework and create a new config as seen in the example I linked to. Or else you would need some other way to access the resource config from the test class. Or you could set up a new server in the test class instead of starting the server in the Main class.

Question:

I am doing something similar to mentioned in Example of using StreamingOutput as Response entity in Jersey

@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response streamExample(@Context UriInfo uriInfo) {
  StreamingOutput stream = new StreamingOutput() {
    @Override
    public void write(OutputStream os) throws IOException,WebApplicationException {
    try{
      Writer writer = new BufferedWriter(new OutputStreamWriter(os));
      //Read resource from jar
      InputStream inputStream = getClass().getClassLoader().getResourceAsStream("public/" + uriInfo.getPath());

      ...//manipulate the inputstream and build string with StringBuilder here//.......
      String inputData = builder.toString();
      Writer writer = new BufferedWriter(new OutputStreamWriter(os));
      writer.write(inputData);
      writer.flush();
    } catch (ExceptionE1) {
        throw new WebApplicationException();
      }
    }
};
  return Response.ok(stream,MediaType.APPLICATION_OCTET_STREAM).build();
}

I am trying to unit test this by mocking URIInfo like mentioned in How to get instance of javax.ws.rs.core.UriInfo

  public void testStreamExample() throws IOException, URISyntaxException {
        UriInfo mockUriInfo = mock(UriInfo.class);
        Mockito.when(mockUriInfo.getPath()).thenReturn("unusal-path");
        Response response = myresource.streamExample(mockUriInfo);}

I want to be able to check that I get an Exception when I switch the path to jar to something else.But, when I run/debug the test, I never enter the

public void write(OutputStream os) throws IOException,
            WebApplicationException {...}

part and I only always hit the return Response.ok(stream,MediaType.APPLICATION_OCTET_STREAM).build();

Am I missing something very obvious here??


Answer:

Because the stream is not written to until it hits the MessageBodyWriter (which is the component that ends up calling the StreamingOutput#write).

What you can do, is just get the Response from the return and call Response#getEntity() (which returns an Object) and cast it to StreamingOutput. Then call the write method yourself, passing an OutputStream, maybe a ByteArrayOutputStream so you can get the contents as a byte[] to check it. It all would look something like

UriInfo mockInfo = mockUriInfo();
Response response = resource.streamExample(mockInfo);
StreamingOutput output = (StreamingOutput) response.getEntity();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.write(baos);
byte[] data = baos.toByteArray();
String s = new String(data, StandardCharsets.UTF_8);
assertThat(s, is("SomeCharacterData"));

Question:

I am writing a test case using JUnit and Mockito for the REST services using jersey. I am getting a null object instead of a mocked object for the Response class.

Code under test

Response response = builder
                        .put( Entity.entity( new ByteArrayInputStream( jsonObj.toString().getBytes() ), MediaType.APPLICATION_JSON ), Response.class );

Test case:

private Invocation.Builder builder; 
private Entity<ByteArrayInputStream> inputStream;
private Response response;
@Before
public void setUp() throws Exception {
    builder = mock( Invocation.Builder.class );
    inputStream = (Entity<ByteArrayInputStream>)mock( Entity.class );
    response = mock( Response.class );
}

@Test
public void myTest() {
when( builder.put( inputStream, Response.class ) ).thenReturn( response );
}

So this line of code gives me a null response. Is there any other way to do this.

Thanks.


Answer:

That is because you are mixing up various things.

Your production code does:

Entity.entity( new ByteArrayInputStream( ...

So, what you got there is:

  • a static call (Entity.entity())
  • a call to new

Both of these operations can not be mocked with Mockito. It is as simple as that.

In order to mock static method calls, you have to look into frameworks such as PowerMock(ito) or JMockit.

But I rather recommend a different solution: consider reworking your production code. Instead making static+new call; create something like

interface EntityProvider {
  public Entity of(bytes[] data, MediaType type);
}

You can easily create an impl class that uses your current code - but for testing purposes, you can dependency-inject a mock of that interface (created via Mockito.mock()); and all of a sudden, your whole code becomes testable with Mockito again.

And no need to look into other mocking frameworks (and imho; at least PowerMockito comes with a certain amount of cost - it is not as simple as "just switch to that other framework").