代码之家  ›  专栏  ›  技术社区  ›  Jan

如何使用moq模拟dbset<t>.load()?

  •  1
  • Jan  · 技术社区  · 7 年前

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

    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。

    我尝试模拟加载()或返回mydbContext.mydbset的值(以便 NullPointerException 不存在)失败

    一个有效的(肮脏的)解决方法是更改tolist()中的load(),但我更希望保留load(),或者至少了解是否有解决方案。事先谢谢你的帮助。解决方案可以是C或vb.net,这对我来说并不重要。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Jevgeni Geurtsen    7 年前

    你已经成功地为 Local ,它是 DbSet<T> 你也嘲笑过的类型。这个 Load 方法是一个静态方法(我相信它甚至是一个扩展方法,但对于本例来说这并不重要)。像moq这样的框架使用代理技术对不同类型的对象进行模拟。虽然这是一个很好的解决方案,但它禁止你嘲笑除 virtual abstract 类型,因此不能模拟静态 负载 方法开箱即用。

    你所能做的就是在你的单元内创建一个新的方法,标记它。 事实上的 并调用 负载 其中的方法:

       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 并修改该类,使其行为符合您的需要。

        2
  •  1
  •   Jan    7 年前

    正如伊万·斯托夫评论中提到的(再次感谢!)我的问题是 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(),则需要通用版本。