【问题标题】:How do I mock IQueryable<T>如何模拟 IQueryable<T>
【发布时间】:2011-01-15 14:22:11
【问题描述】:

我正在创建一个公开 IQueryable 的存储库。为我的单元测试模拟它的最佳方法是什么?

由于我将 RhinoMocks 用于其余的模拟对象,因此我尝试执行以下操作:

IQueryable<MyObject> QueryObject = 
    MockRepository.GenerateStub<IQueryable<MyObject>>();

这不起作用,所以我尝试这样做:

IQueryable<MyObject> QueryObject = 
    (new List<MyObject> { new MyObject() }).AsQueryable();

有没有更好的方法来做到这一点,或者有任何其他模拟框架内置了对 IQueryable 的支持?

我的存储库界面如下所示:

public interface IRepository<T> where T : TableServiceEntity
{
    IQueryable<T> Table { get; }
    void Attach(T existingItem);
    void Delete(T itemToDelete);
    void Insert(T newItem);
    T Load(string partitionKey, string rowKey);
    IEnumerable<T> Load(string partitionKey);
    IEnumerable<T> Query(IQueryable<T> query);
    IEnumerable<T> Last(int count);
    T Last();
    void Update(T item);
}

这是我要测试的方法:

public Post LoadPost(int year, int month, int day, string slug)
{
    var query = from p in _blogRepository.Table
                where 
                    p.PartitionKey == Key.Partition(year, month, day) 
                    && p.Slug == slug
                select p;

    var posts = _blogRepository.Query(query.Take(1));

    return posts.First();
}

然后这是我现在拥有的测试,它将测试 LoadPost。

[Fact]
public void LoadWillRetrieveByPartitionKeyAndRowKeyWhenUsingUriFormat()
{
    Repository
        .Stub(x => x.Query(Arg<IQueryable<Post>>.Is.Anything))
        .Return(new List<Post> {_post});

    var result = Service.LoadPost(
                            _post.Year(),
                            _post.Month(), 
                            _post.Day(), 
                            _post.Slug);

    Assert.NotNull(result);
}

代码取自我的AzureBlog 项目。

【问题讨论】:

    标签: c# mocking rhino-mocks iqueryable


    【解决方案1】:

    我通常会完全按照您在测试中的结果进行操作。在编写测试时,我假设 .Net 库类可以正常工作并且不包含错误,因此我可以在测试中使用它们。当我需要一个测试列表、集合、可查询、字典等时,我只需创建真实的东西并填充测试数据。它使测试更具可读性和编写速度,老实说,风险是不存在的。

    【讨论】:

    • 提供单元测试的代码示例。
    【解决方案2】:

    如果您想模拟您的存储库,您将不会模拟 IQueryable。相反,模拟存储库的方法以返回可用于运行单元测试的固定已知值(如您的第二个示例)。

    【讨论】:

    • 我从这条路线开始,然后在通用存储库上创建了一个特定存储库的额外层。这导致了我的域服务-> 域存储库-> 通用存储库。如果我能够从 Domain Service -> Generic Repository 开始并且仍然可以测试,而不会将实现细节泄漏到 Domain Service 中,我会更开心,因为它需要维护和测试的代码更少。
    • 我明白你在说什么。但是,如果您的问题来自为您的 DomainService 编写单元测试,那么我认为您应该嘲笑 DomainRepository 并且不要担心 Generic Repository(现在)。对 DomainService 进行单元测试最好通过模拟它的依赖项来完成。就 DomainService 而言,它不应该关心 DomainRepository 是如何实现的(即从基类继承)。希望这会有所帮助!
    【解决方案3】:

    我知道这是一个老问题,但只想加我的 2 美分。

    我在使用 SharpLite 生成的存储库时遇到了同样的问题,SharpLite 是我不时使用的一个 ASP .NET MVC 框架。一段时间后,我找到了一个解决方案,唯一的问题是使用 Moq,而不是 Rhino Mocks,但可能你可以找到一种方法来适应它。我做了一个blog post here 来告诉你怎么做。

    它基本上是创建一个实现 IQueryable 的列表并将其用作假数据背景。希望我能帮上忙!

    【讨论】:

    • 在不提供示例的情况下,切勿提供任何地方的链接...您的博客已经消失了。
    • 没有防御!那是很久以前的事了,尽管我可能在 5 到 6 年前就停止使用 .NET,但我想事情已经发生了变化,这可能不再是最佳实践了
    • 现在我们永远不会知道。好吧,你会的。
    【解决方案4】:

    我不确定这是否会对你有所帮助……但我做了你所说的那样。在我的场景中,我有一个使用存储库的数据上下文类。

    我首先创建了一个包含 IQueryable 方法的接口 (IRepository)。然后我创建了两个实现这个接口的类。一个类使用 ORM 进行数据操作 (DbEntityRepository),而另一个类使用类属性 (MemoryRepository)。数据上下文类有一个需要 IRepository 的构造函数。这样做我可以在测试数据上下文时使用 MemoryRepository,我可以在应用程序中使用 DbEntityRepository。

    如果你有兴趣……你可以在 codeplex 上找到代码:IQToolkitContrib

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 2020-12-22
      • 2021-10-15
      • 1970-01-01
      • 2013-09-03
      • 2019-11-21
      • 2011-10-21
      • 1970-01-01
      • 2010-11-18
      相关资源
      最近更新 更多