我如何模拟或测试我的延迟评估/执行功能?

时间:2010-05-18 05:59:47

标签: linq-to-sql testing tdd delegates deferred-execution

我有可能被视为从我的应用程序堆栈传递的IQueryable<T>IList<T>域对象集合的奇怪混合。我试图保持尽可能多的“迟到查询”或“延迟加载”。我这样做有两种方式:

  1. 使用LinqToSql数据层并通过存储库传递IQueryable<T>到我的应用层。
  2. 然后在我的app层传递IList<T>之后,但是对象/聚合图中的某些元素是'chained' with delegates,以便推迟加载。有时,即使代理内容依赖IQueryable<T>来源,也会注入DataContext
  3. 到目前为止,这对我有用。

    令人难以置信的是证明这种设计确实有效。 IE浏览器。如果我在某个地方击败'懒惰'部分并且我的评估/执行发生得很早,那么整个事情就是浪费时间。我想以某种方式TDD这个。

    我对代理或线程安全知之甚少,因为它适用于代理在同一来源上的代理。我希望能够模拟DataContext并以某种方式跟踪延迟(IQueryable<T>的SQL和委托)加载的两种方法,以便我可以进行测试以证明两个函数都在工作在应用程序/堆栈的不同级别/层。

    因为延迟对于设计具有任何价值至关重要,所以当我在给定级别(与实时实现分开)中打破设计时,我希望看到测试失败。这可能吗?

2 个答案:

答案 0 :(得分:4)

morelinq,我们有一个所谓的“打破序列”来测试它。基本上,它是一个枚举器,只要枚举它就会抛出异常。

它可以像以下一样简单:

internal sealed class BreakingSequence<T> : IEnumerable<T>
{
    public IEnumerator<T> GetEnumerator()
    {
        throw new InvalidOperationException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

对它的测试看起来像这样:

   [Test]
    public void XyzIsLazy()
    {
        var source = BreakingSequence<EntityClass>().AsQueryable();

        // inject it as your query source wherever appropriate
        var query = source.Where(x=> true);
        // does not throw, where does not enumerate the sequence
    }

答案 1 :(得分:2)

我将以与Johannes Rudolph所回答的相似的方式回答。听起来你正在思考正确的事情,想要对重要的事情进行测试,如果它失败则难以追踪。

我肯定会建议为此目的使用模拟器。 Johannes提出了一个在枚举时引发异常的对象。由于您的对象是模板化的,我相信您应该能够使用您想要的任何对象。一个模拟框架,如Rhino.Mocks(免费)或TypeMock Isolator(昂贵),可能会非常有用。如果您还没有,我强烈建议您查看模拟框架。

使用模拟手册,您可以评估在运行某些测试代码时,操作应按特定顺序进行。您可以对模拟进行编程以记录发生的操作,然后在测试结束时检查记录。