我正在尝试使用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结婚,所以对任何其他建议持开放态度。
答案 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();
}
}