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 にまんま答えがありました。
以下の通りフラグを立ててやればよいらしいです。
[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)
がコールされました。