2017-08-08 167 views
2

我正在尝试使用Mockito来单元测试使用@NameBinding应用的ContainerRequestFilter。筛选器检查注释字段以确定要执行的操作。 见示例代码:单元测试ContainerRequestFilter与mockito使用ResourceInfo

注释

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

MyEnum

public enum MyEnum { 
    VALUE1, 
    VALUE2, 
    DEFAULT 
} 

注释过滤器,它使用MyEnum作为条件

@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,然后在resourceInfo.getResourceMethod()时返回模拟Method,但由于Method是最终的类,因此无法完成此操作。

也不建议嘲笑你不拥有的对象,那么有没有不同的方法来测试它?我也不喜欢Mockito,所以对其他建议敞开心扉。

回答

1

最简单的方法是刚刚创建的测试虚拟类,并做一些思考,以获得Method的类

@Test 
public void testEnumOne() throws Exception { 
    Method methodOne = MockClass.class.getMethod("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.getMethod("enumOne"); 
     Mockito.when(resourceInfo.getResourceMethod()).thenReturn(methodOne); 

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

    @Test 
    public void testEnumTwo() throws Exception { 
     Method methodTwo = MockClass.class.getMethod("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(); 
    } 
} 
+0

这工作完美。我正在使用Guice,并且必须在'MyFilter'构造函数中注入另一个依赖项。因此,对'ResourceInfo'的'@ Context'注释使用了setter注入。然后在测试设置中,做了'filter.setResourceInfo(resourceInfo)' – bdeo