[英]Testing custom predicate using mocked Exception failing due to incorrect Mock class
I have created a custom Predicate
below and want to test it using mockito
.我在下面创建了一个自定义
Predicate
并想使用mockito
对其进行测试。 I am creating the mocks of the specific exception classes since these dont have public constructor.我正在创建特定异常类的模拟,因为它们没有公共构造函数。 After running the test assert is failing since the
predicate
is returning false
instead of true
.运行测试后断言失败,因为
predicate
返回false
而不是true
。 On printing the class
of the mocked exception it has WebClientResponseException$ServiceUnavailable$MockitoMock$54675
.Seems like the mock is not recognized correctly.在打印模拟异常的
class
时,它有WebClientResponseException$ServiceUnavailable$MockitoMock$54675
。似乎没有正确识别模拟。 Am I doing something wrong here?我在这里做错了什么吗?
PredicateTest谓词测试
@ExtendsWith(MockitoExtention.class)
class PredicateTest{
@InjectMocks
CustomPredicate customPredicate;
@Test
public void testPredicate(){
final ServiceUnavailable serviceUnavailable = mock(ServiceUnAvailable.class);
assertTrue(customPredicate.test(serviceUnavailable))
}
}
CustomPredicate自定义谓词
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);
}
}
Actually the problem is in mock(ServiceUnAvailable.class)
- when you create an object this way it will have a class ServiceUnAvailable$MockitoMock
, not a ServiceUnAvailable.class
, it means that the next your check fill fail:实际上问题出在
mock(ServiceUnAvailable.class)
- 当你以这种方式创建一个 object 时,它将有一个 class ServiceUnAvailable$MockitoMock
,而不是ServiceUnAvailable.class
,这意味着你的下一个检查填充失败:
Predicate<? super Throwable> ClassToControl= throwable -> Exception.contain(throwable.getClass());
Because Exceptions
list doesn't contain element ServiceUnAvailable$MockitoMock
.因为
Exceptions
列表不包含元素ServiceUnAvailable$MockitoMock
。
In order to test exceptions this way I would suggest the next fix (I changed the code a little bit, but I hope the idea is clear):为了以这种方式测试异常,我会建议下一个修复(我稍微更改了代码,但我希望这个想法很清楚):
Predicate:谓词:
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);
}
}
Test:测试:
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 correctly identified the root cause of the problem: @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
On top of his answer, I'd like to suggest more options to change your code:在他的回答之上,我想建议更多选项来更改您的代码:
Let's refactor CustomPredicate:让我们重构 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());
}
}
Fix the test修复测试
You have 2 options, depending if you want your predicate to pass on subclasses:您有 2 个选项,具体取决于您是否希望谓词传递给子类:
All of this assumes that this is dummy code and your Exceptions list is longer.所有这些都假定这是伪代码并且您的例外列表更长。 If you want to test your throwable against one class, a lambda would feel pretty adequate:
如果你想用一个 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
Update: mockito-inline更新:模拟内联
If you use mockito-inline , it changes the way the mocks are constructed:如果你使用mockito-inline ,它会改变模拟的构造方式:
This alternative mock maker which uses a combination of both Java instrumentation API and sub-classing rather than creating a new class to represent a mock.
这个替代模拟制造商使用 Java 工具 API 和子类的组合,而不是创建一个新的 class 来表示模拟。
InlineByteBuddyMockMaker javadoc says: InlineByteBuddyMockMaker javadoc说:
This mock maker will make a best effort to avoid subclass creation when creating a mock.
这个 mock maker 将尽最大努力在创建 mock 时避免创建子类。 Otherwise it will use the
org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker
to create the mock class. That means that the following condition is true否则它将使用
org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker
来创建模拟 class。这意味着以下条件为真class Foo { } assert mock(Foo.class).getClass() == Foo.class;
unless any of the following conditions is met, in such case the mock maker fall backs to the the creation of a subclass.
除非满足以下任何条件,在这种情况下,mock maker 会回退到创建子类。
- the type to mock is an abstract class.
模拟的类型是一个抽象的 class。
- the mock is set to require additional interfaces.
模拟设置为需要额外的接口。
- the mock is explicitly set to support serialization
模拟被显式设置为支持序列化
Thus, if you use mockito-inline the test passes, as there is no subclass created:因此,如果您使用 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
So the issue was I was not having mockito-inline jar in the pom.所以问题是我在 pom.xml 中没有 mockito-inline jar。 Not sure why but this solved the issue
不知道为什么,但这解决了问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.