Mock DbContext.set <T> .Add()EF6

fer*_*res 25 .net c# unit-testing entity-framework moq

我有以下类(其中PilsnerContext是DbContext类):

public abstract class ServiceBase<T> : IService<T> where T: class, IEntity
{
    protected readonly PilsnerContext Context;

    protected ServiceBase(PilsnerContext context)
    {
        Context = context;
    }

    public virtual T Add(T entity)
    {
        var newEntity = Context.Set<T>().Add(entity);
        Context.SaveChanges();
        return newEntity;
    }
}

public class ProspectsService : ServiceBase<Prospect>
{
    public ProspectsService(PilsnerContext context) : base(context){}

}
Run Code Online (Sandbox Code Playgroud)

我正在尝试对Add方法进行单元测试,模拟上下文,如:

[TestClass]
public class ProspectTest
{
    [TestMethod]
    public void AddProspect()
    {
        var mockProspect = new Mock<DbSet<Prospect>>();
        var mockContext = new Mock<PilsnerContext>();

        mockContext.Setup(m => m.Prospects).Returns(mockProspect.Object);

        var prospectService = new ProspectsService(mockContext.Object);

        var newProspect = new Prospect()
        {
            CreatedOn = DateTimeOffset.Now,
            Browser = "IE",
            Number = "1234567890",
            Visits = 0,
            LastVisitedOn = DateTimeOffset.Now
        };

        prospectService.Add(newProspect);

        mockProspect.Verify(m=>m.Add(It.IsAny<Prospect>()), Times.Once);
        mockContext.Verify(m=>m.SaveChanges(), Times.Once);
    }
}
Run Code Online (Sandbox Code Playgroud)

但断言:

mockProspect.Verify(m=>m.Add(It.IsAny<Prospect>()), Times.Once);
Run Code Online (Sandbox Code Playgroud)

失败了,我假设是因为我在Add方法中使用了Context.set().Add()而不是Context.Prospects.Add()但是通过这个测试的正确方法是怎样的?

例外是:

Expected invocation on the mock once, but was 0 times: m => m.Add(It.IsAny<Prospect>()) No setups configured. No invocations performed.
Run Code Online (Sandbox Code Playgroud)

提前致谢.

Pat*_*irk 22

看起来你只是错过了返回你的设置DbSet:

mockContext.Setup(m => m.Set<Prospect>()).Returns(mockProspect.Object);
Run Code Online (Sandbox Code Playgroud)

  • 显然,该方法在[this commit](http://entityframework.codeplex.com/SourceControl/changeset/6dc8879b13f54382eb087dd010636bebc15fdc69)中进行了虚拟,该方法在EF 6.1.0及更高版本中.只是确保我不疯狂! (4认同)

fer*_*res 5

我尝试了你的解决方案Patrick Quirk,但我收到一个错误,告诉我DbContext.Set不是虚拟的.

我在这里找到了解决方案:

如何模拟Entity Framework 6异步方法?

创建DbContext的接口就像

    public interface IPilsnerContext
   {
       DbSet<T> Set<T>() where T : class;
   }
Run Code Online (Sandbox Code Playgroud)

那样我就可以嘲笑它了.

谢谢!

这是我的第一个问题btw,我不确定我是否可以将此问题标记为重复或其他内容.