moq で virtual メソッドをコールする方法

moq を使っていて、ハマったことがあったので備忘録として残しておきます。
主題の通り、「moq で virtual メソッドをコールする方法」です。

やりたかったことと症状

以下のような Dispose パターンを使用したテスト対象のクラスがあったとします。

public class abstract BaseClass : IDisposable
{
    protected virtual void Dispose(bool disposing)
    {
        if(disposing) DisposeCore();
    }

    abstract void DisposeCore();

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

DisposeCore メソッドをモックして、Dispose() 実行時にモックした DisposeCore が呼ばれることをテストしようとした際、virtual な Dispose(bool) がコールされる必要があります。

おそらくコードとしては以下の感じでしょうか。

[Fact]
public void DisposeTest()
{
    var mock = new Mock<BaseClass>();

    mock.Protected().Setup("Dispose", ItExpr.IsAny<bool>()).Callback(()=> /*何かのテスト処理*/);

    mock.Object.Dispose();
}

しかし、このままでは Dispose() 内部でコールされるはずの virtual Dispose(bool) が実行されないのです。

原因と解決方法

原因は、デフォルトでは moq は virtual メソッドは実行されないからっぽいです。

ここまでは、実際の動作からしてそうなんだろうと予想はつくのですが、いかんせん対策方法がわかりません。
で、検索すると、英語版の StackOverflow にまんま答えがありました。

stackoverflow.com

以下の通りフラグを立ててやればよいらしいです。

[Fact]
public void DisposeTest()
{
    var mock = new Mock<BaseClass>();

    mock.Protected().Setup("Dispose", ItExpr.IsAny<bool>()).Callback(()=> /*何かのテスト処理*/);
    mock.CallBase = true; // <- これ!!

    mock.Object.Dispose();
}

実際にこれで、virtual Dispose(bool) がコールされました。

コメント

タイトルとURLをコピーしました