我正在尝试使用Mockito对使用@NameBinding应用的ContainerRequestFilter进行单元测试.过滤器检查注释字段以确定该做什么.
请参阅示例代码:
注解
@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是最终类.
另外,不建议嘲笑您不拥有的对象,因此有其他方法可以测试吗?我也不愿嫁给Mockito,因此欢迎其他建议.
解决方法:
最简单的方法是为测试创建一个虚拟类,并进行一些反射以将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();
}
}