[英]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.