Hot questions for Using Mockito in jax rs

Question:

I'm trying to use Mockito to unit test a ContainerRequestFilter, which is applied using @NameBinding. The filter checks an annotation field to determine what to do. See sample code:

Annotation

@Target({TYPE, METHOD})
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    MyEnum info() default MyEnum.DEFAULT;
}

MyEnum

public enum MyEnum {
    VALUE1,
    VALUE2,
    DEFAULT
}

Annotated Filter which uses MyEnum as conditional

@MyAnnotation
public class MyFilter implements ContainerRequestFilter {

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {

        if (resourceInfo.getResourceMethod().getAnnotation(MyAnnotation.class).info().equals(MyEnum.VALUE1)) 
        {
            // set some value or throw some exception (this can be verified in the test)
        }

        if (resourceInfo.getResourceMethod().getAnnotation(MyAnnotation.class).info().equals(MyEnum.VALUE2))
        {
           // set some value or throw some exception (this can be verified in the test)
        }
    }
}

Annotated Resource methods

@Path("/somepath1")
public class MyResource1
{
    @GET
    @MyAnnotation(info = MyEnum.VALUE1)
    public Response someResourceMethod()
    {
        // return response
    } 
}


@Path("/somepath2")
public class MyResource2
{
    @GET
    @MyAnnotation(info = MyEnum.VALUE2)
    public Response someResourceMethod()
    {
        // return response
    } 
}

This design makes it easy to just add enum values when there are new conditions to be added to the filter.

How can I unit test MyFilter, by varying the values in the conditional?

One approach I tried was to mock ResourceInfo and then return mock Method when resourceInfo.getResourceMethod(), but this cannot be done since Method is a final class.

Also mocking objects you don't own is not recommended, so is there a different approach to test this? I am also not wedded to Mockito, so open to any other suggestions.


Answer:

The easiest way is to just create a dummy class for the test, and do a little reflection to get the Method on the class

@Test
public void testEnumOne() throws Exception {
   Method methodOne = MockClass.class.getDeclaredMethod("enumOne");
   Mockito.when(resourceInfo.getResourceMethod()).thenReturn(methodOne);
}

private static class MockClass {
    @MyAnnotation(info=MyEnum.VALUE1)
    public void enumOne() {}
    @MyAnnotation(info=MyEnum.VALUE2)
    public void enumTwo() {}
}

Here's a complete test.

@RunWith(MockitoJUnitRunner.class)
public class FilterAnnotationTest {

    @Mock
    private ResourceInfo resourceInfo;

    @Mock
    private ContainerRequestContext context;

    @Spy
    private Service service;

    private MyFilter filter;

    @Before
    public void setUp() {
        filter = new MyFilter(resourceInfo, service);
    }

    @Test
    public void testEnumOne() throws Exception {
       Method methodOne = MockClass.class.getDeclaredMethod("enumOne");
       Mockito.when(resourceInfo.getResourceMethod()).thenReturn(methodOne);

       filter.filter(context);
       Mockito.verify(service).methodOne();
    }

    @Test
    public void testEnumTwo() throws Exception {
        Method methodTwo = MockClass.class.getDeclaredMethod("enumTwo");
        Mockito.when(resourceInfo.getResourceMethod()).thenReturn(methodTwo);

        filter.filter(context);
        Mockito.verify(service).methodTwo();
    }


    private enum MyEnum {
        VALUE1, VALUE2
    }

    @Target({ METHOD })
    @Retention(RUNTIME)
    private @interface MyAnnotation {
         MyEnum info();
    }

    private static class MyFilter implements ContainerRequestFilter {

        private final ResourceInfo resourceInfo;
        private final Service service;

        @Inject
        public MyFilter(ResourceInfo resourceInfo, Service service) {
            this.resourceInfo = resourceInfo;
            this.service = service;
        }

        @Override
        public void filter(ContainerRequestContext containerRequestContext) throws IOException {
            MyAnnotation anno = resourceInfo.getResourceMethod().getAnnotation(MyAnnotation.class);
            if (anno.info() == MyEnum.VALUE1) {
                service.methodOne();
            } else if (anno.info() == MyEnum.VALUE2) {
                service.methodTwo();
            }
        }
    }

    private static class MockClass {
        @MyAnnotation(info=MyEnum.VALUE1)
        public void enumOne() {}
        @MyAnnotation(info=MyEnum.VALUE2)
        public void enumTwo() {}
    }

    public interface Service {
        void methodOne();
        void methodTwo();
    }
}

Question:

I am trying to write some unit tests for some code that uses Jersey to hit a RESTful web service, and am using Mockito to mock out some things. Here's my code:

@Test
void test() {
    given:
    // WebResource is a Jersey/JAX-RS construct.
    WebResource mockResource = Mockito.mock(WebResource)

    // Address.groovy is a POJO from my project.
    Address mockAddress = Mockito.mock(Address)

    // THE NEXT LINE IS WHAT IS THROWING THE EXCEPTION:
    Mockito.when(mockResource.get(Mockito.any())).thenReturn(mockAddress)

    when:
    <omitted for brevity>

    then:
    <omitted for brevity>
}

As you can see, I'm trying to coerce Jersey to return my mockAddress instance whenever the WebResource attempts to do an HTTP GET.

When this runs I get:

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method com.sun.jersey.api.client.WebResource$$EnhancerByMockitoWithCGLIB$$1c2e51fa#get.
Cannot resolve which method to invoke for [null] due to overlapping prototypes between:
[class com.sun.jersey.api.client.GenericType]
[class java.lang.Class]
    at groovy.lang.MetaClassImpl.chooseMostSpecificParams(MetaClassImpl.java:3031)
    at groovy.lang.MetaClassImpl.chooseMethodInternal(MetaClassImpl.java:2983)
    at groovy.lang.MetaClassImpl.chooseMethod(MetaClassImpl.java:2926)
    at groovy.lang.MetaClassImpl.getMethodWithCachingInternal(MetaClassImpl.java:1203)
    at groovy.lang.MetaClassImpl.createPojoCallSite(MetaClassImpl.java:3130)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPojoSite(CallSiteArray.java:129)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:163)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at com.me.myapp.MyUnitTest.test(MyUnitTest.groovy:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    <large stack trace omitted for brevity>
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Where MyUnitTest.groovy:19 is the line:

Mockito.when(mockResource.get(Mockito.any())).thenReturn(mockAddress)

Any ideas as to what is going on?


Answer:

WebResource's get() method is overloaded with get(Class) and get(GenericType).

That seems to be where is ambiguity is, as described in the message. That being said, it doesn't really seems appropriate to use Mockito.any(). I'm not a big Mockito user, so I don't know of the normal use cases for using it. When I try to use it with Java, I'll get a compile error, as Mockit.any() will return Object, and neither of the overloaded methods accept Object as an argument.

That being said, the behavior you are mocking, is that when you call get on the WebResource it should return an Address object, so you'll would want to pass Address.class (or Address in the case of Groovy might be OK, as you mentioned in your previous post) to the get method.

Something that should work (at least when I tested with Java) is something like:

WebResource resource = Mockito.mock(WebResource.class);
Address address = Mockito.mock(Address.class);

Mockito.when(resource.get(Address.class)).thenReturn(address);
Mockito.when(address.toString()).thenReturn("Hello World");

Address a = resource.get(Address.class);
System.out.println(a);

This should print out "Hello World"

Question:

I am trying to mock the getResourceClass of javax.ws.rs.container.ResourceInfo. So what i have done is:

ResourceInfo resourceInfo = mock(ResourceInfo.class);

Now when i am trying below:

when(resourceInfo.getResourceClass()).thenReturn(Class.forName("com.p.q.ClassName"));

It throws the below compilation error:

The method thenReturn(Class<capture#1-of ?>) in the type OngoingStubbing<Class<capture#1-of ?>> is not applicable for the arguments (Class<capture#2-of ?>)

Can anybody help me resolving this. Thanks.


Answer:

Not a big Mockito user, so I can't really explain why it doesn't work. But after a little playing around, I found this works

ResourceInfo resourceInfo = Mockito.mock(ResourceInfo.class); 
Mockito.doReturn(YouResourceClass.class).when(resourceInfo).getResourceClass();

Another option

Mockito.<Class<?>>when(resourceInfo.getResourceClass()).thenReturn(YourResource.class);

Question:

I have a class which send video as mp4 file to user (Http request/response) I want to Mock method with main logic to test it. My code

public StreamingOutput videoAsStream(final String videoUrl) {
        try {
            final URL url = new URL(videoUrl);
            return output -> {
                try(final InputStream inputStream = url.openConnection().getInputStream()){
                    IOUtils.copy(inputStream,output);
                    output.close();
                }
            };
        } catch (final MalformedURLException e) {
            log.error("Url exception for url {}",videoUrl);
            throw new UncheckedIOException(e);
        }
    }

What is my way to mock this logic?


Answer:

The problem is, that URL is final, so you will have to use at least Mockito 2 to mock it. If you are ready to do that, I see two possibilities:

a) Give the url into the method and not the string, thus allowing you to put a mocked url in there. That would be the most simply method. You could also then create a 2nd convenience method that creates said URL from a string. Those two methods will be easier to test because their scope is smaller.

b) Extract the final URL url = new URL(videoUrl); part into a new class, for example a URL Factory, then mock that to return a mocked URL object in your test.

As soon as you produce stuff with "new" inside your method, this method can become harder to test, because you now cannot separate this test from this object generation.

Question:

When I try to create a new Object from a Class (annotated with @Provider) I get the following error:

java.lang.ExceptionInInitializerError: null
at xx.xxx.xxx.mapper.AExceptionMapper.<clinit>(AExceptionMapper.java:16)

The Provider looks like:

@Provider
public class AExceptionMapper implements ExceptionMapper<Blupp>

Same if trying to get a Mock via Mockito.


Answer:

Solved, there ware other Errors hidden by this one. After getting Netbeans and Maven back to show them directly and after fixin, the error above disappears

Question:

I can't copy the exact code here but I will put a sample class that explains the problem I am facing.

public XYZ implements ContainerRequestFilter{

    @Context
    HttpServletRequest httpServletRequest;

    @Override
    public void filter(ContainerRequestContext abc){
        //rest of the code below where httpServletRequest is used inside 
    }
}

So when I write a write test code using @InjectMocks, the HttpServletRequest instance is not injected and is null.

Can anyone help me here what I am misssing.

I have even used the following in @Before method but still no resolution.

MockitoAnnotations.initMocks(this);

Answer:

I can verify that it works fine. See below example, where I mock the HttpServletRequest and provide a remote address when getRemoteAddr() is called. I use that mocked value to set a property in the ContainerRequestContext. I then use ArgumentCaptors to capture the value to test.

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Context;

import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

import static org.assertj.core.api.Assertions.assertThat;

public class MockitoInjectMocksTest {

    @Mock
    private HttpServletRequest request;

    @Mock
    private ContainerRequestContext requestContext;

    /**
     * With the @InjectMocks annotation, Mockito will
     * inject the filter with the mock HttpServletRequest
     */
    @InjectMocks
    private Filter filter = new Filter();

    @Before
    public void setUp() {
        // Handle all the mock creation and injection.
        MockitoAnnotations.initMocks(this);

        // Mock the HttpServletRequest#getRemoteAddr()
        // method to return a dummy IP address.
        Mockito.when(request.getRemoteAddr())
                .thenReturn("122.21.32.233");
    }

    /**
     * See the `Filter` class below. The `filter()` method doesn't
     * do much. It just grabs the remote IP address from the
     * `HttpServletRequest` and uses it to set a property on
     * the `ContainerRequestContext`. This test asserts that
     * the arguments passed to the `setProperty()` method
     * method are the correct arguments. We do that with the
     * help of Mockito's `ArgumentCaptor`,
     */
    @Test
    public void testIpPropertySet() throws Exception {
        // Call the `filter()` method that we are testing,
        // passing in the mock `ContainerRequestContext`.
        // We use a mock so that we can later verify methods
        // on it are called
        filter.filter(requestContext);

        // We create argument captors to capture the args of call to
        // `ContainerRequestContext#setProperty(String, String)`
        ArgumentCaptor<String> propNameArg = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> propValArg = ArgumentCaptor.forClass(String.class);

        // Verify the `ContainerRequestContext#setProperty()`
        // is called. We use the `ArgumentCaptors` to capture
        // the arguments that are passed when `setProperty()`
        // is called.
        Mockito.verify(requestContext)
               .setProperty(propNameArg.capture(), propValArg.capture());

        // Test that the arguments passed in the call to
        // `ContainerRequestContext#setProperty()` are correct.
        assertThat(propNameArg.getValue()).isEqualTo("RemoteAddress");
        assertThat(propValArg.getValue()).isEqualTo("122.21.32.233");
    }

    public static class Filter implements ContainerRequestFilter {

        @Context
        private HttpServletRequest request;

        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException {
            System.out.println(request.getRemoteAddr());
            requestContext.setProperty("RemoteAddress", request.getRemoteAddr());
        }
    }
}