使用Mockito模拟异常测试自定义Predicate失败,Mock类识别异常
我编写了如下自定义Predicate,希望使用Mockito对其进行测试。由于目标异常类(ServiceUnavailable)没有公共构造方法,我对该异常类进行了Mock。但运行测试时断言失败,Predicate返回false而非true。打印Mock异常的类名显示为WebClientResponseException$ServiceUnavailable$MockitoMock$54675,看起来Mock未被正确识别。请问我哪里操作有误?
PredicateTest
@ExtendsWith(MockitoExtension.class) class PredicateTest{ @InjectMocks CustomPredicate customPredicate; @Test public void testPredicate(){ final ServiceUnavailable serviceUnavailable = mock(ServiceUnavailable.class); assertTrue(customPredicate.test(serviceUnavailable)); } }
CustomPredicate
class CustomPredicate implements Predicate<Throwable>{ private static final List<Class<?>> EXCEPTIONS = Arrays.asList(WebClientResponseException.ServiceUnavailable.class); private static final Predicate<? super Throwable> CLASS_TO_CONTROL = throwable -> EXCEPTIONS.contains(throwable.getClass()); @Override public boolean test(Throwable t){ return ExceptionUtils.getThrowableList(t).stream().anyMatch(CLASS_TO_CONTROL); } }
问题出在Mockito生成的Mock对象是原类的动态子类,所以throwable.getClass()返回的是类似WebClientResponseException$ServiceUnavailable$MockitoMock$xxxx的子类,而不是你在EXCEPTIONS列表中存放的WebClientResponseException.ServiceUnavailable.class,自然匹配失败。
修复方法有两种:
改用
Class.isAssignableFrom()判断类型兼容性
把CLASS_TO_CONTROL的判断逻辑改成检查异常类是否是目标类的子类或本身:private static final Predicate<? super Throwable> CLASS_TO_CONTROL = throwable -> EXCEPTIONS.stream().anyMatch(clazz -> clazz.isAssignableFrom(throwable.getClass()));这样不管是原类对象还是Mockito生成的子类Mock对象,都能被正确识别。
使用反射创建原异常实例(如果可行)
如果不想修改Predicate逻辑,可以尝试通过反射调用ServiceUnavailable的私有构造方法创建真实实例,而不是Mock:@Test public void testPredicate() throws Exception { Constructor<WebClientResponseException.ServiceUnavailable> constructor = WebClientResponseException.ServiceUnavailable.class.getDeclaredConstructor(int.class, String.class, HttpHeaders.class, byte[].class, Charset.class); constructor.setAccessible(true); WebClientResponseException.ServiceUnavailable serviceUnavailable = constructor.newInstance(503, "Service Unavailable", HttpHeaders.EMPTY, new byte[0], StandardCharsets.UTF_8); assertTrue(customPredicate.test(serviceUnavailable)); }这种方式能拿到真实的异常类实例,匹配逻辑不需要修改,但依赖反射,需要注意构造方法参数是否正确。
内容的提问来源于stack exchange,提问作者ghostrider

