如何在單元測試中優雅地Mock ILogger

在撰寫單元測試時,難免會遇到需要測物件和Logger互動的情況,有些類別需要Logger才能完成他的職責。舉個情境,我們希望Printer Class可以在Log中記錄印了幾頁。

身為一個單元測試愛好者,當然要寫測試驗證功能符合需求。我們使用NSub將ILogger的介面mock掉,並在Print(pages)結束後,檢查列印的結果。

上面的測試會正常通過,但僅限於這種參數完全一樣比對的情況,如果遇到複雜一點,需要用到Arg.Is加上Lambda expression的時候,會出現問題。

此時測試會拋出落落長的例外訊息

這個錯誤訊息的意思是說,你對某個method用了Arg.Is或Arg.Any,但因為寫法有問題,所以Arg.Is或Arg.Any並沒有發生作用。

NSubstitute只能夠替換掉virtual method,而_Logger.LogInformation是個extension method,因此不能mock掉。

可是第一個測試是成功的,之前的logger.Received(1).LogInformation("2")是怎麼mock的呢?

實際上,你mock掉的是ILogger<TCategory>介面上的的Log<TState>方法。

大概等價於

但實際上,上面這一段的寫法是不work的。FormattedLogValues是Log Library的internal class,沒辦法也不該直接在你的測試中使用拿來用的。

想要優雅Mock ILogger,我們可以使用一個抽象類,實作ILogger<T>

之後,測試就可以優雅地使用NSub提供的Argument Matcher語法,做LogLevel和內容的判斷。

希望這篇文幫助到需要Mock ILogger介面的朋友:),一起優雅地寫測試吧

Reference:
https://medium.com/@whuysentruit/unit-testing-ilogger-in-asp-net-core-9a2d066d0fb8

2 thoughts on “如何在單元測試中優雅地Mock ILogger

  1. 提外話,在 .NET Core 裡面,如果你不管 logger 的話,內建有一個 Nulllogger 可以用

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *