簡體   English   中英

使用模擬異常測試自定義謂詞由於不正確的模擬而失敗 class

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

  • test() 將 wraps 輸入轉換為 1 元素列表,將其轉換為 stream,並使用 anyMatch 運行測試。 這是令人困惑和不必要的。
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 個選項,具體取決於您是否希望謂詞傳遞給子類:

  • 將 ServiceUnavailable 的實際實例傳遞給 test()(使用 new 而不是模擬)
  • 在測試中使用 instanceof 檢查(使用 stream 和 anyMatch,但在例外列表中)

所有這些都假定這是偽代碼並且您的例外列表更長。 如果你想用一個 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM