单元测试ContainerRequestFilter,它使用ResourceInfo和mockito

时间:2017-08-08 19:24:59

标签: java unit-testing jersey jax-rs mockito

我正在尝试使用Mockito对使用@NameBinding应用的ContainerRequestFilter进行单元测试。过滤器检查注释字段以确定要执行的操作。 请参阅示例代码:

注释

declare @t table (id int, NegativeOnlyHours int, [difference] float); -- original table
insert into @t values(437, 0, 23.5), (442, -4, -4), (447, 0, 1), (452, 0, 9.5);

-- SOLUTION:
with cte
as
(
select 1 as Num, id, NegativeOnlyHours, [difference], CASE when [difference]>0 then 0 else [difference] END as answer  
    from (select ROW_NUMBER() over(order by id) as num, id, NegativeOnlyHours, [difference] from @t) t1 where num = 1
union all
(select cte.Num + 1, t.id, t.NegativeOnlyHours, t.[difference], 
    CASE
        WHEN answer + t.[difference] > 0 THEN 0
        ELSE answer + t.[difference]
    END as answer 
 from cte 
join (select ROW_NUMBER() over(order by id) as num, id, NegativeOnlyHours, [difference] from @t) t 
on t.NUM = cte.Num + 1)
)
select id, NegativeOnlyHours, [difference], answer from cte;

MyEnum

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

使用MyEnum作为条件的带注释的过滤器

public enum MyEnum {
    VALUE1,
    VALUE2,
    DEFAULT
}

带注释的资源方法

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

这种设计可以在有新条件添加到过滤器时轻松添加枚举值。

如何通过改变条件中的值来单元测试@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 } }

我尝试过的一种方法是模拟MyFilter,然后在ResourceInfo时返回模拟Method,但由于Method是最终类,因此无法完成此操作。

也不推荐嘲笑你不拥有的对象,所以有不同的方法来测试它吗?我也不会和Mockito结婚,所以对任何其他建议持开放态度。

1 个答案:

答案 0 :(得分:4)

最简单的方法是为测试创建一个虚拟类,并进行一些反思以获得类Method

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

这是一个完整的测试。

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