Moqを使用して、最初に呼び出されたときに例外をスローし、2回目に呼び出されたときに成功するメソッドをモックする最も簡潔な方法は何ですか?
Callback
を利用し、カウンターをインクリメントして、Callback
から例外をスローするかどうかを決定します。
[Test]
public void TestMe()
{
var count = 0;
var mock = new Mock<IMyClass>();
mock.Setup(a => a.MyMethod()).Callback(() =>
{
count++;
if(count == 1)
throw new ApplicationException();
});
Assert.Throws(typeof(ApplicationException), () => mock.Object.MyMethod());
Assert.DoesNotThrow(() => mock.Object.MyMethod());
}
public interface IMyClass
{
void MyMethod();
}
Moq 4.2以降では、組み込みメソッドSetupSequence()
を使用できます(@RichardBarnettのコメントで述べられています)。
例:
var mock = new Mock<IMyClass>();
mock.SetupSequence(x => x.MyMethod("param1"))
.Throws<MyException>()
.Returns("test return");
私がこれまでに思いついた最高のものはこれです:
interface IFoo
{
void Bar();
}
[Test]
public void TestBarExceptionThenSuccess()
{
var repository = new MockRepository(MockBehavior.Default);
var mock = repository.Create<IFoo>();
mock.Setup(m => m.Bar()).
Callback(() => mock.Setup(m => m.Bar())). // Setup() replaces the initial one
Throws<Exception>(); // throw an exception the first time
...
}
Phil Haackは、特定の結果シーケンスを返すメソッドの設定について興味深い ブログ投稿 を持っています。特定のタイプの値のシーケンスの代わりに、タイプTまたは例外の結果のシーケンスが必要になるため、いくつかの作業が必要な場合は、開始点として適しているようです。