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.
Mockito is a mocking framework, JAVA-based library that is used for effective unit testing of JAVA applications. Mockito is used to mock interfaces so that a dummy functionality can be added to a mock interface that can be used in unit testing.
In other words: you can definitely use JUnit without using a mocking framework. Same is true for the reverse direction; but in reality, there are not many good reasons why you would want to use Mockito for anything else but unit testing.
Mockito requires you to provide all arguments either by matchers or by exact values. So if a method has more than one argument and you want to use argument matchers for only some of its arguments, forget it.
The Mockito. mock() method allows us to create a mock object of a class or an interface. We can then use the mock to stub return values for its methods and verify if they were called. We don't need to do anything else to this method before we can use it.
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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With