Moqにタスクを返すように指示するにはどうすればよいですか?


327

宣言するインターフェースを持っています

Task DoSomethingAsync();

私のテストではMoqFrameworkを使用しています:

[TestMethod()]
public async Task MyAsyncTest()
{
   Mock<ISomeInterface> mock = new Mock<ISomeInterface>();
   mock.Setup(arg => arg.DoSomethingAsync()).Callback(() => { <my code here> });
   ...
}

次に、テストでを呼び出すコードを実行しますawait DoSomethingAsync()。そして、テストはその行で失敗します。何が悪いのですか?


5
その行のテストエラーを言うと、どのようなエラーが発生しますか?
AlSki、2014年

@AlSkiはおそらくNullReferenceExceptionです。あなたが見ることができるように、ここで
LuckyLikey

回答:


709

メソッドにはコールバックがないため、使用する理由はありません.CallBack()。次のように.Returns()Task.FromResultを使用して、目的の値を持つタスクを返すだけです。

MyType someValue=...;
mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.FromResult(someValue));

2014-06-22の更新

Moq 4.2には、これを支援する2つの新しい拡張メソッドがあります。

mock.Setup(arg=>arg.DoSomethingAsync())
    .ReturnsAsync(someValue);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .ThrowsAsync(new InvalidOperationException());

更新2016-05-05

Seth Flowersが他の回答で言及しているように、ReturnsAsyncを返すメソッドでのみ使用できますTask<T>。タスクのみを返すメソッドの場合、

.Returns(Task.FromResult(default(object)))

に使える。

この回答に示されているように、.NET 4.6では、次のように簡略化されています.Returns(Task.CompletedTask);

mock.Setup(arg=>arg.DoSomethingAsync())        
    .Returns(Task.CompletedTask);

16
.Returns(Task.CompletedTask); それが私の答えでした
Todd Vance

8
Moqフレームワークが更新を受け取ったので、この回答を最新に保つためにありがとう!
Jacob Stamm

.Returns(Task.FromResult(default(object))戻り値の型がvoidの場合にうまく機能します。 .Returns(Task.FromResult(null as MyType))期待される戻り値の型がnullの場合にうまく機能します。
ジェレミーレイブラウン

1
私が説明するように、@ JeremyRayBrownは.NET 4.6 default(object)では不要になりました。参照型である限りnull as MyType同じです。default(MyType)MyType
Panagiotis Kanavos

40

同様の問題

私はおおよそ次のようなインターフェースを持っています:

Task DoSomething(int arg);

症状

テスト中のサービスawaitedがへの呼び出しを行ったときに、ユニットテストが失敗しましたDoSomething

修正

受け入れ答えとは違って、あなたが呼び出すことができない.ReturnsAsync()あなたにSetup()この方法は、非ジェネリックを返すため、このシナリオでは、この方法のTaskではなく、Task<T>

ただし、.Returns(Task.FromResult(default(object)))セットアップでは引き続き使用でき、テストに合格できます。


1
これについて考えてみてください。非ジェネリックタスク(.net 4.6以外)を返す必要がある場合は、Taskを返す簡単な方法としてTask.Delay(1)を返すことを検討します。時間の引数を増やすことで、作業を模倣することもできます。
stevethethread 2016

26

.Returns(Task.FromResult(0));コールバックの後に追加するだけです。

例:

mock.Setup(arg => arg.DoSomethingAsync())
    .Callback(() => { <my code here> })
    .Returns(Task.FromResult(0));

4

これで、Talentsoft.Moq.SetupAsyncパッケージhttps://github.com/TalentSoft/Moq.SetupAsyncも使用でき ます

どちらの答えのベースにここに発見し、アイデアは部品番号に提案が、それでもまだ、ここで実装されていません:https://github.com/moq/moq4/issues/384、非同期メソッドの大幅簡素化セットアップを

SetupAsync拡張機能を使用して実行された以前の応答で見つかったいくつかの例:

mock.SetupAsync(arg=>arg.DoSomethingAsync());
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Callback(() => { <my code here> });
mock.SetupAsync(arg=>arg.DoSomethingAsync()).Throws(new InvalidOperationException());
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.