模拟DbSet.AddOrUpdate

Ben*_*bin 4 c# moq entity-framework-6

我下面的说明这里试试我的嘲笑DbSetDbContext单元测试使用起订量.

我正在测试的服务看起来像这样

public class MyItemService
{
   private MyContext context;

   public void AddItem(MyItem item)
   {
      this.context.MyItems.AddOrUpdate(item);
      this.context.SaveChanges();
   }
}
Run Code Online (Sandbox Code Playgroud)

我的单元测试看起来像这样

[TestMethod]
public void AddItem_ShouldSucceed()
{
    var myItems = new Mock<DbSet<MyItem>>();

    var context = new Mock<MyContext>();
    context.Setup(e => e.MyItems).Returns(myItems.Object);          

    MyItemService service = new MyItemService(context.Object);

    service.AddItem(new MyItem
    {
        Id = "1234"
    });
}
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,我得到了例外

System.InvalidOperationException: Unable to call public, instance method AddOrUpdate on derived IDbSet<T> type 'Castle.Proxies.DbSet``1Proxy'. Method not found.

我认为问题是因为AddOrUpdate是一个扩展方法DbSet.我确实已经System.Data.Entity.Migrations包含在我的测试.cs文件中.

我尝试添加该行

myItems.Setup(e => e.AddOrUpdate(It.IsAny<MyItem>()));
Run Code Online (Sandbox Code Playgroud)

到我的单元测试,但后来我得到了例外

System.NotSupportedException:Expression引用不属于模拟对象的方法:e => e.AddOrUpdate(new [] {It.IsAny()})

当我测试的方法正在使用时,有什么方法可以让我的单元测试工作AddOrUpdate

Win*_*Win 8

在寻找类似问题后,我遇到了这个老问题.

所有我们需要做的是创造MockableDbSetWithExtensions抽象类,并用它来代替DbSet,每当你要测试的调用方法AddOrUpdate.

实体框架团队也是如何测试他们的代码的.

public abstract class MockableDbSetWithExtensions<T> : DbSet<T>
    where T : class
{
    public abstract void AddOrUpdate(params T[] entities);
    public abstract void AddOrUpdate(Expression<Func<T, object>> 
         identifierExpression, params T[] entities);
}
Run Code Online (Sandbox Code Playgroud)

用法

[TestMethod]
public void AddItem_ShouldSucceed()
{
    var myItems = new Mock<MockableDbSetWithExtensions<MyItem>>();

    var context = new Mock<MyContext>();
    context.Setup(e => e.MyItems).Returns(myItems.Object);

    MyItemService service = new MyItemService(context.Object);

    ...
}
Run Code Online (Sandbox Code Playgroud)