如何使用NSubstitute模拟DbContext然后添加/删除数据

时间:2016-09-14 10:34:36

标签: c# entity-framework dbcontext nsubstitute dbset

我需要模仿EF DbContext。我使用the approach here并且效果很好。

// mock a DbSet
var mockDbSet = Substitute.For<DbSet<Foo>, IQueryable<Foo>>();
var data = new List<Foo>().AsQueryable();
((IQueryable<Foo>)mockDbSet).Provider.Returns(data.Provider);
((IQueryable<Foo>)mockDbSet).Expression.Returns(data.Expression);
((IQueryable<Foo>)mockDbSet).ElementType.Returns(data.ElementType);
((IQueryable<Foo>)mockDbSet).GetEnumerator().Returns(data.GetEnumerator());
// now add it to a mock DbContext
var mockContext = Substitute.For<MyDbContextClass>();
mockContext.Set<Foo>().Returns(mockDbSet);

然而,在某些测试中,我需要能够调用mockContext.Set<Foo>().Add(someFoo)mockContext.Set<Foo>().Remove(otherFoo),并使底层的添加/删除逻辑起作用。

我试过了:

mockDbSet.When(x => x.Add(Arg.Any<Foo>())).Do(x => data.Add(x.Arg<Foo>()));

但会引发Collection was modified; enumeration operation may not execute.

那么如何实现添加/删除功能?

2 个答案:

答案 0 :(得分:5)

您不想将其添加到收藏中。你想要做的是检查它是否被调用(添加/删除/等)以及可能被调用的内容。

// arrange - check what it was called with. You place asserts in the body of the `Do` expression. Place this before your call that actually executes the code
mockDbSet.Add(Arg.Do<Foo>(foo =>
{
    Assert.IsNotNull(foo);
    // Assert other properties of foo
}));

// act


// assert. Make sure that it was actually called
mockDbSet.Received(1).Add(Arg.Any<Foo>());

如果您希望稍后在测试中添加Foo,则可以保留对List的{​​{1}}的引用。

Foo

答案 1 :(得分:0)

@Stilgar的评论让我看看EntityFramework.Testing库,它解决了this very problem

所以我用这个库替换了我的东西(不用担心了)。