メソッドの戻り値では検証ができないようなケースで、処理内部のログが出力されている/出力されていないによって、予期した通りの動きになっているかをテストしたかった。
Moq の Verify によって、該当ログが出力されているかどうかを確認することで実現する。
環境
- Visual Studio 2019
- .NET Core 3.1
準備
- Visual Studio で 「xUnit テストプロジェクト(.NET Core)」を作成
- 作成したテストプロジェクトに、NuGet パッケージの管理から「Moq」をインストール
実装
テスト対象
Target.cs
public class Hoge
{
private readonly ILogger<Hoge> logger;
public Hoge(ILogger<Hoge> logger) => this.logger = logger;
public bool Fuga()
{
try
{
// なんかの処理1
// ~~~
logger.LogInformation("処理1終わったよ");
// なんかの処理2
// ~~~
logger.LogInformation("処理2終わったよ");
return true;
}
catch
{
logger.LogError("例外発生しちゃたよ");
return false;
}
}
}
テストコード
UnitTest.cs
public class HogeTest
{
private Mock<ILogger<Hoge>> loggerMock = new Mock<ILogger<Hoge>>();
[Fact]
public void SuccessTest()
{
// 正常終了する条件で Fuga 実行
new Hoge().Fuga();
// なんかの処理1ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Information
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("処理1終わったよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Once); // このログが1回出力されることの確認
// なんかの処理2ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Information
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("処理2終わったよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Once); // このログが1回出力されることの確認
// 例外ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Error
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("例外発生しちゃたよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Never); // このログが出力されないことの確認
}
[Fact]
public void ExceptionTest()
{
// なんかの処理2で例外が発生する条件で Fuga 実行
new Hoge().Fuga();
// なんかの処理1ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Information
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("処理1終わったよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Once); // このログが1回出力されることの確認
// なんかの処理2ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Information
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("処理2終わったよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Never); // このログが出力されないことの確認
// 例外ログの確認
loggerMock.Verify(l => l.Log(LogLevel.Error
, It.IsAny<EventId>()
, It.Is<It.IsAnyType>((object o, Type _) => o.ToString().Contains("例外発生しちゃたよ"))
, null
, (Func<It.IsAnyType, Exception, string>)It.IsAny<object>())
, Times.Once); // このログが1回出力されることの確認
}
}
該当ログメッセージが出力されるか否かを Verify することで、外部から検証し辛い内部の動きを確認することができる。