Debug.Assert与Code Contract的使用

时间:2013-12-16 04:30:00

标签: c# assert code-contracts

我应该何时在代码合同上调试。或者反之亦然?我想检查一个方法的前提条件,我很困惑,选择一个而不是另一个。我有单元测试,我想测试故障情况并期望例外。

在同一方法上使用Debug.Assert和Code契约是一个好习惯。如果是这样,代码的编写顺序是什么?

Debug.Assert(parameter!= null);
Contract.Requires<ArgumentNullException>(parameter != null, "parameter");

Contract.Requires<ArgumentNullException>(parameter != null, "parameter");
Debug.Assert(parameter!= null);

背后有什么理由吗?

2 个答案:

答案 0 :(得分:30)

这些是不同的东西。调试断言仅在代码编译为调试时执行,因此仅在调试时检查/断言。我们的想法是将此用于您正在开发的代码的“健全性检查”。代码契约可以在调试或发布中使用。他们确保方法的前后条件符合方法的期望(符合合同)。还有一个提供类似功能的测试框架,用于检查测试合规性。

当您需要确保在开发代码时(以及在以后的维护开发中)确保某些内容符合您的预期时,请使用Debug.Assert。

如果要确保调试和发布中的条件均为真,请使用代码协定。合同还允许某些形式的静态分析,这有助于验证您的程序是否“正确”。

在创建单元测试时使用Testing框架断言。

答案 1 :(得分:24)

就我个人而言,我不会同时使用Debug.Assert和代码合同来强制执行新编写的代码中的先决条件 - IMO代码合同取代Debug.Assert,因为它们提供了更全面的检查套件,更不用说了可以从静态检查中获得的好处,可以在代码运行时之前执行。在Debug.AssertContracts中维护重复的前置条件检查将非常麻烦。

理由:

  • 您无需重新编码可能已在Debug.Assertthrow代码中编码的任何旧前提条件 - 您可以保留现有的前提条件检查代码和terminate it with Contract.EndContractBlock()
  • 如果您在合同运行时检查设置为System.Diagnostics.Debug的情况下构建,则/d:DEBUG在没有None的情况下构建时,您可以获得相同的未经检查的“发布模式”行为。 Ref 6.2.1 in the Docs
  • 合同允许开发人员在代码中更加表达“为什么”检测到无效状态 - 例如直接是因为带外参数(Contract.Requires)。否则Contract.AssertContract.Assume可以检查一般状态,并且可以使用Contract.Ensures表示离开方法时状态的“保证正确性”。 Invariants表示必须始终保持国家。
  • 最重要的是,静态检查可以在您构建代码时强制执行这些合同 - 这样您就有机会通过设计时间或编译时警告来获取错误,而不必等待运行时间。可以将合同检查添加到持续集成中以查找不合规情况。

有一点需要注意:如果您要编写故​​意违反合同的单元测试,您可能需要处理ContractException - Jon Skeet很好地解释了这一点here。例如将测试设置中的Contract.ContractFailed handler连接到调用SetHandled的处理程序,然后抛出一个公共异常,您可以在UT中捕获并断言。