[英]I am trying to mock a final java class using Mockito 2, class is getting mocked but I still get Unfinished Stubbing Exception
[英]Testing custom predicate using mocked Exception failing due to incorrect Mock class
我在下面创建了一个自定义Predicate
并想使用mockito
对其进行测试。 我正在创建特定异常类的模拟,因为它们没有公共构造函数。 运行测试后断言失败,因为predicate
返回false
而不是true
。 在打印模拟异常的class
时,它有WebClientResponseException$ServiceUnavailable$MockitoMock$54675
。似乎没有正确识别模拟。 我在这里做错了什么吗?
谓词测试
@ExtendsWith(MockitoExtention.class)
class PredicateTest{
@InjectMocks
CustomPredicate customPredicate;
@Test
public void testPredicate(){
final ServiceUnavailable serviceUnavailable = mock(ServiceUnAvailable.class);
assertTrue(customPredicate.test(serviceUnavailable))
}
}
自定义谓词
CustomPredicate implements Predicate<Throwable>{
private static final List<Class<?>> Exceptions= Arrays.asList(WebClientResponseException.ServiceUnavailable.class);
private static final Predicate<? super Throwable> ClassToControl= throwable -> Exception.contain(throwable.getClass());
@Override
public boolean test(Throwable t){
return ExceptionUtils.getThrowableList(t).stream().anyMatch(ClassToControl);
}
}
实际上问题出在mock(ServiceUnAvailable.class)
- 当你以这种方式创建一个 object 时,它将有一个 class ServiceUnAvailable$MockitoMock
,而不是ServiceUnAvailable.class
,这意味着你的下一个检查填充失败:
Predicate<? super Throwable> ClassToControl= throwable -> Exception.contain(throwable.getClass());
因为Exceptions
列表不包含元素ServiceUnAvailable$MockitoMock
。
为了以这种方式测试异常,我会建议下一个修复(我稍微更改了代码,但我希望这个想法很清楚):
谓词:
public class CustomPredicate implements Predicate<Throwable> {
private final List<Class<?>> exceptions;
private final Predicate<? super Throwable> classToControl;
public CustomPredicate(Class<?>... exceptions) {
this(Arrays.asList(exceptions));
}
public CustomPredicate(List<Class<?>> exceptions) {
this.exceptions = exceptions;
this.classToControl = throwable -> this.exceptions.contains(throwable.getClass());
}
@Override
public boolean test(final Throwable throwable) {
return ExceptionUtils.getThrowableList(throwable).stream()
.anyMatch(classToControl);
}
}
测试:
public class PredicateTest {
@Test
public void testPredicate() {
final IllegalStateException serviceUnavailable = Mockito.mock(IllegalStateException.class);
CustomPredicate customPredicate = new CustomPredicate(serviceUnavailable.getClass());
assertTrue(customPredicate.test(serviceUnavailable));
}
}
@VolodyaLombrozo 正确地确定了问题的根本原因:
var serviceUnavailableMock = mock(ServiceUnavailable.class);
System.out.println(serviceUnavailableMock.getClass());
System.out.println(serviceUnavailableMock.getClass() == ServiceUnavailable.class);
System.out.println(serviceUnavailableMock instanceof ServiceUnavailable);
// class org.example.ServiceUnavailable$MockitoMock$X21NGyAU
// false
// true
在他的回答之上,我想建议更多选项来更改您的代码:
让我们重构 CustomPredicate:
public class CustomPredicate implements Predicate<Throwable> {
private static final List<Class<?>> Exceptions = List.of(ServiceUnavailable.class);
@Override
public boolean test(Throwable t) {
return Exceptions.contains(t.getClass());
}
}
修复测试
您有 2 个选项,具体取决于您是否希望谓词传递给子类:
所有这些都假定这是伪代码并且您的例外列表更长。 如果你想用一个 class 来测试你的 throwable,一个 lambda 就足够了:
Predicate<Throwable> pThrowable1 = t -> t instanceof ServiceUnavailable; // if you care about subclasses
Predicate<Throwable> pThrowable2 = t -> ServiceUnavailable.class.equals(t.getClass()); // if you want strict equality
更新:模拟内联
如果你使用mockito-inline ,它会改变模拟的构造方式:
这个替代模拟制造商使用 Java 工具 API 和子类的组合,而不是创建一个新的 class 来表示模拟。
InlineByteBuddyMockMaker javadoc说:
这个 mock maker 将尽最大努力在创建 mock 时避免创建子类。 否则它将使用
org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker
来创建模拟 class。这意味着以下条件为真class Foo { } assert mock(Foo.class).getClass() == Foo.class;
除非满足以下任何条件,在这种情况下,mock maker 会回退到创建子类。
- 模拟的类型是一个抽象的 class。
- 模拟设置为需要额外的接口。
- 模拟被显式设置为支持序列化
因此,如果您使用 mockito-inline 测试通过,因为没有创建子类:
var serviceUnavailableMock = mock(ServiceUnavailable.class);
System.out.println(serviceUnavailableMock.getClass());
System.out.println(serviceUnavailableMock.getClass() == ServiceUnavailable.class);
System.out.println(serviceUnavailableMock instanceof ServiceUnavailable);
// class org.example.ServiceUnavailable
// true
// true
所以问题是我在 pom.xml 中没有 mockito-inline jar。 不知道为什么,但这解决了问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.