基于合同的编程与单元测试


13

我是一个有点防御性的程序员,并且是Microsoft代码合同的忠实拥护者。

现在我不能总是使用C#,在大多数语言中,我唯一拥有的工具就是断言。所以我通常会得到这样的代码:

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

但是,这种范式(或您所说的任何范式)会导致很多代码混乱。

我开始怀疑这是否值得付出努力,是否已经进行了适当的单元测试?


6
尽管单元测试允许将断言从应用程序代码中移出(并因此避免混乱),但是请考虑它们无法检查实际生产系统中可能发生的一切。因此,IMO代码合同具有一些优势,尤其是对于正确性特别重要的关键代码。
乔治

因此,基本上是开发时间,可维护性,可读性与更好的代码覆盖率?
ronag 2013年

1
我主要在代码中使用断言来检查参数的正确性(例如,在null上),而在单元测试中还要检查那些断言。
artjom 2013年

Answers:


14

我认为您不应该将其视为“ vs”。
正如@Giorgio的评论中所提到的那样,代码合同应检查(在生产环境中)不变式,而单元测试则应确保在满足这些条件时代码按预期方式工作。


2
我认为它也是重要考验是否代码工作(例如,它抛出一个异常)时的条件没有得到满足。
svick 2013年

6

合同至少可以帮助您完成单元测试无法做到的一件事。在开发公共API时,您无法单元测试人们如何使用您的代码。但是,您仍然可以为方法定义合同。

我个人只会在处理模块的公共API时对合同如此严格。在其他许多情况下,这样做可能不值得(您可以使用单元测试),但这只是我的观点。

这并不意味着我建议在这种情况下不要考虑合同。我一直在想他们。我只是认为不必始终对它们进行显式编码。


1

如前所述,合同和单元测试具有不同的目的。

合同是关于防御性编程的,以确保满足先决条件,使用正确的参数调用代码等。

单元测试以确保代码在不同的场景下都能正常工作。这些就像“牙齿规格”。

断言是好的,它们可以使代码健壮。但是,如果您担心它会增加很多代码,则可能还希望在调试过程中的某些位置添加条件断点并减少Assert计数。


0

您可以通过测试完成checkVariants()调用中的所有操作,实际上可以付出多少努力取决于很多事情(外部依赖项,耦合级别等),但是从一个角度来看,它可以清理代码。我不确定没有断言就针对断言开发的代码库如何可测试。

我同意@duros,不应将它们视为排他性或竞争性方法。实际上,在TDD环境中,您甚至可以认为“需求”断言将需要进行测试:)。

但是,断言不会使代码更健壮,除非您实际进行一些工作来修复失败的检查,否则断言它们通常只是通过在出现问题的第一个迹象时中止处理来阻止数据损坏或类似情况。

经过测试驱动/经过良好测试的解决方案通常会在开发交互组件的过程中已经考虑和/或发现许多不良输入和输出的来源/原因,并已在更接近问题根源的地方对其进行了处理。

如果您的源是外部的,并且您无法对其进行控制,那么为避免使代码混乱以处理其他代码问题,您可以考虑在源和您的组件之间实施某种数据清洗/声明组件,并将检查放在其中。

另外,我很好奇您使用的是什么语言,而这些语言没有某人开发的某种xUnit或其他测试库,我认为这些天来几乎都有很多东西吗?


0

除了单元测试和代码合同外,我只是想强调另一个方面,它是定义接口的价值,这样您就可以消除或减少一开始就错误地调用代码的可能性。

这并不总是容易或可能的,但是绝对值得问自己一个问题:“我可以使此代码更加安全吗?”

C#的创建者Anders Hejlsberg说,C#的最大错误之一就是不包括非空引用类型。这是太多必要的保护代码混乱的主要原因之一。

但是,根据我的经验,重构仅具有必要和足够数量的保护代码将使代码更加可用和可维护。

同意@duros的其余部分。


0

两者都可以,但是要使用一些静态辅助方法来阐明您的意图。这就是Google针对Java所做的事情,请查看code.google.com/p/guava-libraries/wiki/PreconditionsExplained

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.