【问题标题】:How can I mock a method of a returned mock object?如何模拟返回的模拟对象的方法?
【发布时间】:2014-11-20 14:09:23
【问题描述】:

我是 Moq 的新手。我正在对实体框架 6 项目进行单元测试,遵循here 提供的指导。所以我有一个模板化的方法来创建假表:

    protected Mock<DbSet<TheType>> MockDBSet<TheType>(List<TheType> data) where TheType : class
    {
        var mockSet = new Mock<DbSet<TheType>>();
        var dataSet = data.AsQueryable();
        mockSet.As<IQueryable<TheType>>().Setup(m => m.Provider).Returns(dataSet.Provider);
        mockSet.As<IQueryable<TheType>>().Setup(m => m.Expression).Returns(dataSet.Expression);
        mockSet.As<IQueryable<TheType>>().Setup(m => m.ElementType).Returns(dataSet.ElementType);
        mockSet.As<IQueryable<TheType>>().Setup(m => m.GetEnumerator()).Returns(dataSet.GetEnumerator());
        mockSet.Setup(x => x.Add(It.IsAny<TheType>()))
            .Returns(new Func<TheType, TheType>(x =>
            {
                data.Add(x);
                return data.Last();
            }));

        return mockSet;
    }

使用上述方法可以很好地添加和查询假数据库:

var db = new Mock<BloggingContext>();
db.Setup(m => m.Blog s).Returns(MockDBSet<Blog >(
    new List<Blog>() 
).Object);

BloggingContext context = db.Object;

Blog blog= new Blog();
context.Blogs.Add(blog); //fine
Assert.IsTrue(context.Blogs.Count() == 1); //fine

EF 还在实体集合上提供了“本地”属性,可以访问未保存的实体。因此,当不模拟时,BloggingContext.Blogs.Local 会传回未保存实体的 ObservableCollection 集合。调用 BloggingContext.SaveChanges() 时,对象会从 BloggingContext.Blogs.Local 移动到 BloggingContext.Blogs。

我想模拟这种行为,所以我创建了一个新类:

    public class FakeBlogs : List<Blog>
    {
        ObservableCollection<Blog> _local = new ObservableCollection<Blog>();
        ObservableCollection<Blog> Local { get { return _local; } }

        public void Add (Blog item)
        {
            _local.Add(item);
        }
    }

单元测试时,以下代码有效:

var db = new Mock<BloggingContext>();
db.Setup(m => m.Blog s).Returns(MockDBSet<Blog>(
    new FakeBlogs() //<===== Changed to use FakeBlogs
).Object);

BloggingContext context = db.Object;

Blog blog= new Blog();    
context.Blogs.Add(blog); //fine
Assert.IsTrue(context.Blogs.Count() == 1); //fine

但是,使用 Local 属性会引发 NPE,因为 Local 属性为 null。

var blog = (from i in context.Blogs.Local select i).FirstOrDefault();//throws NPE

如何成功模拟 Local 属性?

【问题讨论】:

  • 欢迎来到 StackOverflow!请参阅"Should questions include “tags” in their titles?",其中的共识是“不,他们不应该”。
  • 真的是context.Blogs null,还是在评估表达式时调用的东西?你能提供你的异常的堆栈跟踪吗?
  • 它的 context.Blogs.Local 为空。 context.Blogs 很好。异常详情如下: System.ArgumentNullException 发生 HResult=-2147467261 Message=Value 不能为空。参数名称:source Source=System.Core ParamName=source StackTrace: at System.Linq.Enumerable.Where[TSource](IEnumerable1 source, Func2 predicate) at InnerException:

标签: c# entity-framework unit-testing moq


【解决方案1】:

已修复。我在 MockDBSet 模板函数中添加了以下行:

        mockSet.Setup(m => m.Local).Returns(data.Local);

并将 FakeTable 的“Local”属性声明为 public。感谢所有感兴趣的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多