使用 Pex、Contracts 和 QuickGraph 进行误报单元测试

发布于 2024-10-14 18:24:52 字数 2439 浏览 2 评论 0原文

每个人。我在合约、pex 和 Quickgraph 之间有一个令人困惑的交互,非常感谢更有知识的人的建议。我将其归结为一个重现案例,其中注释掉一个合同会使误报消失,但我无法在允许的时间内使用调试器诊断它,因为主题代码(quickgraph)在属性方面有副作用 - getter,这意味着调试器在显示属性值时会执行副作用,从而干扰实际的执行顺序。

首先是一些背景知识,然后是具体细节,然后是一个可供下载和尝试的项目的指针,如果您愿意深入了解的话!

我安装了 Pex &鼹鼠

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

和 CodeContracts for .NET 4.0

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

我通过 nuget 下载了最新版本的 QuickGraph,它都是为 .NET 3.5 构建的。我将其修剪到我需要的最低限度,进入所有项目属性,将它们从 .NET 3.5 Client Profile 全部更新到 .NET 4.0,修复了一个源代码破坏性更改(这是微不足道的,而且非常非常不可能与我的项目有任何联系)问题)。然后,我转到每个项目页面上的“代码合同”选项卡并启用所有静态和动态选项。

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

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

http://dl.dropbox.com/ 获取我的项目 zip 文件u/1997638/QuickGraph.zip

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

该测试练习了一个图形构造函数,该构造函数通过在 Edges 和 EdgeCount 的属性获取器中调用用户提供的委托来动态构建边。可爱的。但是 IImplicitUndirecteGraphContracts.cs 第 49 行的合约出现了问题。

这是一个误报,因为如果我注释掉这个合同,测试就会通过。在尝试在调试器中遵循这一点时,它与属性 getter 中创建 Edge 的时间有关。然而,我无法解开这个问题,因为调试器调用这些 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>);
  }

everyone. I have a perplexing interaction between contracts, pex, and quickgraph and would be very grateful for advice from the more knowledgeable. I have boiled it down to a repro case where commenting out one contract makes the false negative go away, but I have been unable to diagnose it with the debugger in the time allowed because the subject code (quickgraph) has side-effects in property-getters, meaning that the debugger executes the side effects when displaying the values of the properties, interfering with the actual order of execution.

First a little background, then the specifics, then a pointer to a project to download and try out, should you be so inclined as to dig in!

I installed Pex & Moles

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

and CodeContracts for .NET 4.0

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

I downloaded, via nuget, the most recent version of QuickGraph, which is all built for .NET 3.5. I pruned it to the minimum I needed, went into Project Properties for all, updated them all to .NET 4.0 from .NET 3.5 Client Profile, fixed one source breaking change (which was trivial and very, very unlikely to have any connection to my problem). I then went to the Code Contracts tab on every project page and enabled all static and dynamic options.

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

The project has 192 unit tests, many of them Pex-generated (very nice!). To run the tests, get my project zip file from

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

Make sure you have Pex & Moles and Contracts from the links above. Open the solution, Rebuild everything, then, at the solution level, "Run All Tests In Solution" (control-R, A). All will pass. Then go to line 49 of IImplicitUndirectedGraphContracts.cs and uncomment the Contract under the large comment (inserted by me). One test, Prim12240WithDelegate will fail.

That test exercises a graph constructor that builds edges on-the-fly by calling a user-supplied delegate in the property-getters for Edges and EdgeCount. Cute. But something goes wrong with the Contract on line 49 of IImplicitUndirecteGraphContracts.cs.

This is a false negative, because if I comment out this contract, the test passes. In trying to follow this in the debugger, it has something to do with the timing of the creation of the Edges in the property getters. I haven't been able to disentangle this, however, because the debugger calls these getters, the subject code calls them, the contracts code calls them, maybe statically, maybe dynamically, I just plain got lost trying to follow it, and thought I'd bring the question up to those who understand the details of contract execution better than I.

Here is the offending contract; commenting it out makes the unit test succeed:

[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>);
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

谁把谁当真 2024-10-21 18:24:53

Pex 在处理 .NET 4.0 运行时中的 LINQ 表达式时存在问题。来自 此 MSDN 论坛帖子的第一个答案了解更多详情

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

为什么 Pex 无论如何都无法与 Linq 抗衡:简而言之,Linq 使用
DynamicMethod 用于生成代码。 DynamicMethod 方法不是
当它们被抖动时向分析器报告。因为我们的分析器
无法在 DynamicMethod 中注入回调,Pex 无法跟踪
通过 Linq 查询的数据流。我们有一个拦截的解决方法
Linq to Object 编译器的内部结构并强制它使用
改为 Reflection.Emit。

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

Pex has issues dealing with LINQ expressions in the .NET 4.0 runtime. from the first answer on this MSDN forum post for more details:

Our Linq support works for .NET 2.0/3.5 but we seem to have a
regression for .NET4.0. If you are running 4.0, that would explain why
Pex cannot generate interresting test cases - we don't instrument Linq
correctly.

Why does Pex struggle with Linq anyway: in a nutshell, Linq uses
DynamicMethod's to generate code. DynamicMethod methods are not
reported to the profiler when they are jitted. Because our profiler
cannot inject callbacks in the DynamicMethod, Pex cannot track the
data flow through the Linq query. We have a workaround that intercepts
the internals of the Linq to Object compiler and forces it to use
Reflection.Emit instead.

This could have potentially made it ignore the Contract that you have commented out during its evaluation, leading to the false negative.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文