如何使用Moq模拟DbSet <t> .Load()?

时间:2018-11-29 13:58:46

标签: .net vb.net entity-framework moq

我正在尝试对以下代码行进行单元测试:

myDbContext.myDbSet.Load()
myObservableCollection = myDbContext.myDbSet.Local

我的测试方法如下:

Dim dataMyDbSet = New List(Of myDbSet) From {
        new myDbSet() With{.Id=1},
        new myDbSet() With{.Id=1},
        new myDbSet() With{.Id=1}
        }.AsQueryable()

Dim myDbSetMock = New Mock(Of DbSet(of myDbSet))
myDbSetMock.As(of IQueryable (Of myDbSet)).Setup(Function(m) m.Provider).Returns(dataMyDbSet.Provider)
myDbSetMock.As(of IQueryable (Of myDbSet)).Setup(Function(m) m.Expression).Returns(dataMyDbSet.Expression)
myDbSetMock.As(of IQueryable (Of myDbSet)).Setup(Function(m) m.ElementType).Returns(dataMyDbSet.ElementType)
myDbSetMock.As(of IQueryable (Of myDbSet)).Setup(Function(m) m.GetEnumerator).Returns(dataMyDbSet.GetEnumerator)

myDbSetMock.Setup(Function(x) x.Local).Returns(New ObservableCollection(Of myDbSet)(dataMyDbSet))

Dim MyDbContextMock = New Mock(of dbCrashtestNcap)
MyDbContextMock.Setup(function (f) f.myDbSet).Returns(myDbSetMock.Object)

Dim crashService = New CrashService(MyDbContextMock.Object)
Dim result = crashService.GetOcNcapKlassen()

Assert.That(result.Count,[Is].EqualTo(3))

这使我在第一行使用myDbContext.myDbSet.Load()获得NullReferenceException

我所有尝试模拟Load()或为myDbContext.myDbSet返回值(从而使NullPointerException不存在)的尝试均失败了

一个可行的解决方法是更改​​ToList()中的Load(),但我希望保留Load()或至少了解是否有解决方案。在此先感谢您的帮助。解决方案可能是C#或vb.net,这对我来说并不重要

2 个答案:

答案 0 :(得分:1)

您已经成功为Local设置了模拟,它是DbSet<T>类型的一个属性,您也已经对其进行了模拟。 Load方法是静态方法(我相信它甚至是扩展方法,但在这种情况下都没有关系)。 Moq等框架使用代理技术来为不同类型的对象设置模拟。尽管这是一个不错的解决方案,但是它禁止您模拟virtualabstract类型以外的任何内容,因此您不能使用Moq来开箱即用地模拟静态Load方法。

您可以做的是在单元内部创建一个新方法,将其标记为virtual,然后在其中调用Load方法:

   public class Unit
    {
        public void YourMethod()
        {
            // .. do stuff
            CallStaticMethod(/* maybe pass parameters? */);
            // .. do more stuff
        }

        public virtual void CallStaticMethod()
        {
            // call static method
            Console.WriteLine("This is a static method call!");
        }
    }

    public class UnitUnderTest : Unit
    {
        public override void CallStaticMethod()
        {
            // do whatever you want during testing only

            // possibly call base.CallStaticMethod() to execute base method.
        }
    }

现在在单元测试中,您需要使用UnitUnderTest并修改该类以使其符合您的需求。

答案 1 :(得分:1)

正如Ivan Stoev的评论中所述(再次感谢!),我的问题是Load()不能在IQueryable的通用版本上运行,而不能在非通用版本上运行。因此,为解决此问题,我用以下内容替换了上面的四行,并且可以正常工作:

myDbSetMock.As(of IQueryable).Setup(Function(m) m.Provider).Returns(dataMyDbSet.Provider)
myDbSetMock.As(of IQueryable).Setup(Function(m) m.Expression).Returns(dataMyDbSet.Expression)
myDbSetMock.As(of IQueryable).Setup(Function(m) m.ElementType).Returns(dataMyDbSet.ElementType)
myDbSetMock.As(of IQueryable).Setup(Function(m) m.GetEnumerator).Returns(dataMyDbSet.GetEnumerator)

但是,如果要使用ToList(),则需要通用版本。