2016-11-17 110 views
1

驗證SLF4J我有SLF4J記錄器類實例化,如:嘲諷與JMockit

public class MyClass { 

    private static final Logger log = LoggerFactory.getLogger(MyClass.class); 

    public void foo() { 
     log.warn("My warn"); 
    } 
    } 

而且我需要JMockit進行測試,如:

@Test 
public void shouldLogWarn(@Mocked Logger log) throws Exception { 
    new Expectations() {{ 
    log.warn(anyString); 
    }}; 
    MyClass my = new MyClass(); 
    my.foo(); 
} 

搜索了很多我想通了之後,我需要以某種方式使用MockUp。但不能確切地得到它。

順便說一句,我正在使用JMockit(1.29)的最後一個版本,你不能再爲最終靜態字段設置setField(log)

回答

2

JMockit有適用於這種情況的@Capturing註釋。

指示模擬字段或模擬參數,所有延伸/實現模擬類型的類都將被模擬。

未來捕獲模擬類型的實例(即在測試過程中稍後創建的實例)將與模擬字段/參數關聯。在模擬字段/參數上記錄或驗證期望值時,這些相關實例被視爲等同於爲模擬字段/參數創建的原始模擬實例。

這意味着,如果你有@Capturing,而不是@Mocked,註釋它是試運行期間創建的每個Logger將與一個你標註的關聯。所以下面的工作:

@Test 
public void shouldLogWarn(@Capturing final Logger log) throws Exception { 
    // This really ought to be a Verifications block instead 
    new Expectations() {{ 
    log.warn(anyString); 
    }}; 
    MyClass my = new MyClass(); 
    my.foo(); 
} 

作爲一個側面說明,如果你想要做的就是驗證的方法被調用時,最好使用Verifications代替,因爲這是它是什麼打算。所以,你的代碼應該是這樣的:

@Test 
public void shouldLogWarn(@Capturing final Logger log) throws Exception { 
    MyClass my = new MyClass(); 
    my.foo(); 
    new Verifications() {{ 
    log.warn(anyString); 
    }}; 
} 

注: JMockit 1.34 1.38,通過該has a bug防止了這種從slf4j-log4j12工作,並可能SLF4J的其他依賴。如果遇到此錯誤,請升級到1.39或更高版本。

+0

非常感謝!此外,在這種情況下,必須添加'@Mocked LoggerFactory未使用',因爲如果真正的LoggerFactory試圖與模擬記錄器一起工作,沒有獲得NPE。 – mergoth

+0

@mergoth如果您的代碼使用靜態方法,那麼嘲笑LoggerFactory是不必要的。所以'私有靜態最終記錄器日誌= LoggerFactory.getLogger(MyClass.class);'事實上,我看到你正在使用它,所以我不知道爲什麼你需要一個LoggerFactory的模擬實例。我在代碼中使用完全相同的東西,但不需要模擬LoggerFactory。 – Thunderforge

+0

如果LoggerFactory未被模擬,getLogger()方法會嘗試獲取記錄器實例,並最終與NPE一起死亡,同時將已模擬的Logger實例放置到logback lib深處的非null強制Map中。 – mergoth