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()
メソッドの目標を達成するにはどうすればよいですか?