web-dev-qa-db-ja.com

IAsyncEnumerableをどのようにモックしますか?

IAsyncEnumerable<T>を返すサービスの別のメソッドを呼び出すメソッドを単体テストしたい。サービスMock<MyService>のモックを作成しました。このモックを設定したいのですが、方法がわかりません。出来ますか ? IAsyncEnumerableの再調整を呼び出すメソッドを単体テストする他の方法はありますか

public async Task<List<String>> MyMethodIWantToTest()
{
  var results = new List<string>();
  await foreach(var item in _myService.CallSomethingReturningAsyncStream())
  {
    results.Add(item);
  }
  return results;
}
4
TechWatching

これを解決する1つの方法は、同期的に列挙されるIEnumerableをラップする専用のテストクラスを使用することです。

TestAsyncEnumerable.cs

internal class TestAsyncEnumerable<T> : List<T>, IAsyncEnumerable<T>
{
   public TestAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }

   public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new TestAsyncEnumerator<T>(GetEnumerator());
}

internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
   private readonly IEnumerator<T> _inner;

   public TestAsyncEnumerator(IEnumerator<T> inner)
   {
      _inner = inner;
   }

   public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(_inner.MoveNext());

   public T Current => _inner.Current;

   public ValueTask DisposeAsync()
   {
      _inner.Dispose();

      return new ValueTask(Task.CompletedTask);
   }
}

使用法:

[Fact]
public async Task MyTest() {
   var myItemRepository = A.Fake<IMyItemRepository>();

   A.CallTo(       () => myRepository.GetAll())
    .ReturnsLazily(() => new TestAsyncEnumerable<MyItem>(new List<MyItem> { new MyItem(), ... }));


   //////////////////
   /// ACT & ASSERT
   ////////
}
0
silkfire