【发布时间】:2011-05-01 17:57:48
【问题描述】:
使用 .NET 4.0 代码合同执行 TDD 的最佳实践建议是什么?
我想具体来说,我的问题是,鉴于 TDD 的一点是允许代码自我记录并且合同现在提供了文档的一部分,是否应该以与其他代码相同的方式测试代码合同?
【问题讨论】:
标签: .net c#-4.0 code-contracts
使用 .NET 4.0 代码合同执行 TDD 的最佳实践建议是什么?
我想具体来说,我的问题是,鉴于 TDD 的一点是允许代码自我记录并且合同现在提供了文档的一部分,是否应该以与其他代码相同的方式测试代码合同?
【问题讨论】:
标签: .net c#-4.0 code-contracts
这取决于您使用合同的方式以及您正在开发的应用程序类型。
首先:您当然不想单独测试断言和后置条件(Contract.Assert、Contract.Assume、Contract.Ensures 和 Contract.EnsuresOnThrow)。
我认为这样做没有实际价值 - 因为它们已经在运行时由重写器验证,即使没有测试,您也会很快发现失败。
然而,在一个经过良好测试的应用程序中,任何后置条件或断言都不应该失败——即使在无效输入上也是如此。因此,如果您的所有测试(甚至是那些测试无效数据处理的测试!)在没有单个后置条件/断言失败的情况下通过,则您的后置条件和断言可以被视为“经过测试”。
为此,您可能希望在测试中使用“Assert.Fail”来处理 ContractFailed 事件。
现在“有趣”的部分是先决条件:
你在开发图书馆吗?然后,如果您的时间/预算允许,您绝对应该测试它们(更糟糕的是不测试实际逻辑)。
特别是,如果您使用“Contract.Requires
如果您不是在编写库,我不会说测试前置条件真的很有必要——它们不是真正的业务需求,而是调试的助手。
如果参数是null,则为方法应该抛出的每个ArgumentNullException编写一个单元测试会变得非常无聊。
如果您在方法中忘记了这个验证代码(意思是:特定的 Contract.Requires),您可能也会忘记单元测试。因此,参数验证测试为您的(非库)代码带来的附加值与连接值相比非常低。
总结一下:不要测试后置条件和断言。测试先决条件 - 但仅限于库(以及可能像库一样使用的部分代码)。
【讨论】:
我将不同意这里的其他一些人。契约不是测试,它们是关于 API 要求和承诺的断言。它们不会神奇地证明您的代码是正确的,它们只是在您违反合同时在运行时为您提供信息。我不了解你,但我不想发布在某些极端情况下未能遵守合同并因合同断言而崩溃的代码!像任何其他行为一样,合约应该进行单元测试。如果您不执行合同(以及间接执行合同的代码路径),您就没有代码有效性的证据。代码契约和单元测试不是相互排斥的概念。
【讨论】:
很好的问题。简单回答是不。代码契约可以处理与系统行为无关的多余测试。如果您真的可以达到 100% 的代码覆盖率,您将需要处理 isnull 检查等。这些检查不需要在您的测试套件中。额外的好处是这些将在编译时检查,而不是等待测试执行。
希望这会有所帮助。
【讨论】:
Pex 是结合代码合同创建单元测试的有用工具。它分析您的代码并为其生成基本单元测试。最棒的是它能够识别和理解代码契约,从而适应它生成的测试代码。
如果您有 MSDN 订阅,则可以下载 Pex/Moles 作为 powertool,否则您可以在 http://research.microsoft.com/en-us/projects/pex/downloads.aspx 下载它(不是最新版本)。
【讨论】:
测试是为了测试代码的行为是否符合预期
您不应明确编写测试来执行合同断言。
但是,在 TDD 中或进行代码更改时,运行单元测试可能会以导致合约失败的方式执行代码 - 当这种情况发生时,测试应该会失败,并且您希望能够找到符合条件的合约快速轻松地失败,因此您可以更正代码。
所以你想以某种方式捕获一个合同异常,如果只是做一个 Asser.Fail("Contract requirements not met")
这可能是你所追求的更多 How to Log error while using Code Contracts
【讨论】: