3

NSubstituteを使用して、DbSetをモックして Entity Framework 6.x を単体テストしたいと思います。幸いなことに、Scott Xuは優れた単体テスト ライブラリEntityFramework.Testing.Moq using Moqを提供しています。それで、私は彼のコードを NSubstitute に適したものに変更しました。これまでのところDbSet<T>.Add()DbSet<T>.Remove()メソッドをテストしたいと思うまでは良さそうです。ここに私のコードビットがあります:

public static class NSubstituteDbSetExtensions
{
  public static DbSet<TEntity> SetupData<TEntity>(this DbSet<TEntity> dbset, ICollection<TEntity> data = null, Func<object[], TEntity> find = null) where TEntity : class
  {
    data = data ?? new List<TEntity>();
    find = find ?? (o => null);

    var query = new InMemoryAsyncQueryable<TEntity>(data.AsQueryable());

    ((IQueryable<TEntity>)dbset).Provider.Returns(query.Provider);
    ((IQueryable<TEntity>)dbset).Expression.Returns(query.Expression);
    ((IQueryable<TEntity>)dbset).ElementType.Returns(query.ElementType);
    ((IQueryable<TEntity>)dbset).GetEnumerator().Returns(query.GetEnumerator());

#if !NET40
    ((IDbAsyncEnumerable<TEntity>)dbset).GetAsyncEnumerator().Returns(new InMemoryDbAsyncEnumerator<TEntity>(query.GetEnumerator()));
    ((IQueryable<TEntity>)dbset).Provider.Returns(query.Provider);
#endif

    ...

    dbset.Remove(Arg.Do<TEntity>(entity =>
                                 {
                                   data.Remove(entity);
                                   dbset.SetupData(data, find);
                                 }));

    ...

    dbset.Add(Arg.Do<TEntity>(entity =>
                              {
                                data.Add(entity);
                                dbset.SetupData(data, find);
                              });

    ...

    return dbset;
  }
}

そして、次のようなテストメソッドを作成しました:

[TestClass]
public class ManipulationTests
{
  [TestMethod]
  public void Can_remove_set()
  {
    var blog = new Blog();
    var data = new List<Blog> { blog };

    var set = Substitute.For<DbSet<Blog>, IQueryable<Blog>, IDbAsyncEnumerable<Blog>>()
                        .SetupData(data);

    set.Remove(blog);

    var result = set.ToList();

    Assert.AreEqual(0, result.Count);
  }
}

public class Blog
{
   ...
}

この問題は、テスト メソッドが を呼び出すときに発生しますset.Remove(blog)InvalidOperationExceptionのエラーメッセージをスローします

コレクションが変更されました。列挙操作が実行されない場合があります。

これは、メソッドが呼び出さdataれたときに偽のオブジェクトが変更されているためです。set.Remove(blog)ただし、元のスコットの使用方法Moqでは問題は発生しません。

したがって、set.Remove(blog)メソッドをtry ... catch (InvalidOperationException ex)ブロックでラップし、catchブロックが何もしないようにすると、テストは (もちろん) 例外をスローせず、期待どおりに渡されます。

これが解決策ではないことはわかっていますが、単体テストDbSet<T>.Add()DbSet<T>.Remove()メソッドの目標を達成するにはどうすればよいですか?

4

1 に答える 1