简体   繁体   English

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

[英]How do I mock DbContext using NSubstitute and then add/remove data

I need to mock EF's DbContext . 我需要模拟EF的DbContext I use the approach here and it works well. 在这里使用该方法,并且效果很好。

// 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);

However in some tests I need to be able to call mockContext.Set<Foo>().Add(someFoo) and mockContext.Set<Foo>().Remove(otherFoo) , and for the underlying add/remove logic to work. 但是在某些测试中,我需要能够调用mockContext.Set<Foo>().Add(someFoo)mockContext.Set<Foo>().Remove(otherFoo) ,并使基础的添加/删除逻辑起作用。

I tried this: 我尝试了这个:

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

but it throws with Collection was modified; enumeration operation may not execute. 但是它与Collection was modified; enumeration operation may not execute.抛出时Collection was modified; enumeration operation may not execute. Collection was modified; enumeration operation may not execute.

So how do I implement add/remove functionality? 那么如何实现添加/删除功能?

You don't want to add it to the collection. 您不想将其添加到集合中。 What you want to do is check if it (add/remove/etc) was called and possibly what it was called with. 您想要做的就是检查它(添加/删除/等)是否被调用,以及调用它的可能。

// 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>());

If you want to add a Foo at a later point in your test you can keep the reference to the List of Foo 's. 如果要在以后的测试中添加Foo ,则可以保留对Foo List的引用。

// mock a DbSet
var mockDbSet = Substitute.For<DbSet<Foo>, IQueryable<Foo>>();
var fooList = new List<Foo>();
var data = fooList.AsQueryable();
// rest of your code unchanged

// add it from the code being tested through the mock dbset
mockDbSet.Add(Arg.Do<Foo>(foo =>
{
    fooList.Add(foo);
    // at this point you have to recreate the added IQueryable
    data = fooList.AsQueryable();
    // rest of code you had to add this to the mockDbSet
}));


// act

The comment by @Stilgar made me look into the EntityFramework.Testing library, which solves this very problem . @Stilgar的评论使我了解了EntityFramework.Testing库,它解决了这个问题

So I replaced my stuff with this library (one less thing to worry about). 所以我用这个库替换了我的东西(不用担心的另一件事)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM