1

每个人。我在合同、pex 和 quickgraph 之间有一个令人困惑的交互,非常感谢知识渊博的人提供的建议。我把它归结为一个复制案例,其中注释掉一个合同会使假阴性消失,但我无法在允许的时间内用调试器诊断它,因为主题代码(快速图)对属性有副作用- getters,意味着调试器在显示属性值时执行副作用,干扰实际执行顺序。

首先是一点背景,然后是细节,然后是一个可以下载和试用的项目的指针,如果您愿意深入研究的话!

我安装了 Pex & Moles

http://research.microsoft.com/en-us/projects/pex/downloads.aspx

和 .NET 4.0 的 CodeContracts

http://research.microsoft.com/en-us/projects/contracts/

我通过 nuget 下载了最新版本的 QuickGraph,它都是为 .NET 3.5 构建的。我将它修剪到我需要的最低限度,进入所有项目属性,将它们全部从 .NET 3.5 客户端配置文件更新到 .NET 4.0,修复了一个源中断更改(这是微不足道的,非常非常不可能与我的问题)。然后我转到每个项目页面上的 Code Contracts 选项卡并启用所有静态和动态选项。

http://quickgraph.codeplex.com/releases/view/55262

该项目有 192 个单元测试,其中许多是 Pex 生成的(非常好!)。要运行测试,请从

http://dl.dropbox.com/u/1997638/QuickGraph.zip

确保您有来自上述链接的 Pex & Moles 和 Contracts。打开解决方案,重建所有内容,然后在解决方案级别,“在解决方案中运行所有测试”(control-R,A)。一切都会过去的。然后转到 IImplicitUndirectedGraphContracts.cs 的第 49 行并取消注释大注释下的合同(由我插入)。一项测试 Prim12240WithDelegate 将失败。

该测试通过在 Edges 和 EdgeCount 的属性获取器中调用用户提供的委托来运行图形构造函数。可爱的。但是 IImplicitUndirecteGraphContracts.cs 第 49 行的 Contract 出了点问题。

这是一个假阴性,因为如果我注释掉这个合同,测试就通过了。在调试器中尝试遵循这一点时,它与在属性 getter 中创建边缘的时间有关。然而,我无法解开这个问题,因为调试器调用这些 getter,主题代码调用它们,合约代码调用它们,可能是静态的,也可能是动态的,我只是迷失了试图遵循它,并认为我会向那些比我更了解合同执行细节的人提出这个问题。

这是违规合同;将其注释掉会使单元测试成功:

[Pure]
  IEnumerable<TEdge> IImplicitUndirectedGraph<TVertex, TEdge>.AdjacentEdges(TVertex v)
  {
    IImplicitUndirectedGraph<TVertex, TEdge> ithis = this;
    Contract.Requires(v != null);
    Contract.Requires(ithis.ContainsVertex(v));
    Contract.Ensures(Contract.Result<IEnumerable<TEdge>>() != null);
~~~~~~> Contract.Ensures(
      Enumerable.All(
        Contract.Result<IEnumerable<TEdge>>(),
        edge => 
          edge != null && 
          ithis.ContainsEdge(edge.Source, edge.Target) && 
          (edge.Source.Equals(v) || edge.Target.Equals(v))
        )
      );
    return default(IEnumerable<TEdge>);
  }
4

1 回答 1

1

Pex 在处理 .NET 4.0 运行时中的 LINQ 表达式时存在问题。从这个 MSDN 论坛帖子的第一个答案中了解更多详细信息

我们的 Linq 支持适用于 .NET 2.0/3.5,但我们似乎对 .NET4.0 有一个回归。如果您运行的是 4.0,这可以解释为什么 Pex 无法生成有趣的测试用例 - 我们没有正确检测 Linq。

为什么 Pex 仍然与 Linq 斗争:简而言之,Linq 使用 DynamicMethod 生成代码。DynamicMethod 方法在 jitted 时不会报告给分析器。因为我们的分析器无法在 DynamicMethod 中注入回调,所以 Pex 无法通过 Linq 查询跟踪数据流。我们有一个解决方法,它拦截 Linq to Object 编译器的内部并强制它使用 Reflection.Emit。

这可能会使其忽略您在评估期间注释掉的合同,从而导致误报。

于 2011-07-24T21:08:18.617 回答