次のクラスとそれに依存するインターフェイスがあるとします。
_public class MyController
{
private IRepository _repository;
public MyController(IRepository repository)
{
_repository = repository;
}
public async Task MethodUnderTest(int someId)
{
var o = await _repository.FindById(someId);
// update o
await _repository.Commit();
}
}
public interface IRepository
{
Task Commit();
}
_
このメソッドを単体テストすると、次のことができます(xUnitとRhino Mocksを使用)。
_[Fact]
public async Task MyTest()
{
IRepository repositoryStub = MockRepository.GenerateStub<IRepository>();
MyController controller = new MyController(repositoryStub);
await controller.MethodUnderTest(1);
}
_
これはSystem.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていませんで失敗します。
次のStackTraceの場合:
_UnitTest.MyController.<MethodUnderTest>d__0.MoveNext() in
\UnitTest\Class1.cs:line 35
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at \UnitTest\Class1.cs:line 20
_
Commit()
がnull
を返し、非同期/待機用に生成されたステートマシンがnull
でMoveNext()
を呼び出すため、このエラーが発生することは正しいですか?
私は次のようなことをすることでこれを修正できます:
_repositoryStub.Expect(r => r.Commit()).Return(Task.FromResult<bool>(true);
_
しかし、これは少し奇妙に感じます。_FromResult<T>
_には任意のT
を使用でき、テストが実行されます。ジェネリックでないFromResult
を返すTask
メソッドが見つかりません。
T
に何を使用するかは重要ですか?それとも他の方法で修正する必要がありますか?
何かを返す必要があります。 _async Task
_メソッドはnull
を返すことができません。
T
は関係ありません。必要に応じて、static readonly Task SuccessTask = Task.FromResult<object>(null);
をヘルパー定数として宣言できます。 AsyncExライブラリに 類似の定数 があります。
.NET Framework 4.6以降をターゲットにしている場合は、代わりに.Returns(Task.CompletedTask)
を使用できますが、これは少し短いです。