代码之家  ›  专栏  ›  技术社区  ›  Adam Bellaire

契约式设计和测试驱动开发

  •  27
  • Adam Bellaire  · 技术社区  · 17 年前

    我正在努力改进我们团队的开发过程,我正在考虑如何最好地通过测试驱动开发实现契约式设计。这两种技术似乎有很多重叠之处,我想知道是否有人对以下(相关)问题有一些见解:

    • 除非您使用某种代码生成器来生成基于契约的单元测试,否则使用TDD和DbC不是违反DRY原则吗?否则,您必须在两个地方维护合同(测试和合同本身),或者我遗漏了什么?
    • 仅使用TDD而不是将TDD与DbC结合使用是否更容易/更灵活?

    如果我们已经正确地进行了TDD,那么如果我们也使用DbC,我们的开销会有很大的好处吗?

    有几个细节,尽管我认为这个问题在很大程度上与语言无关:

    • 我们的团队非常小,<10名程序员。
    • 我们主要使用Perl。
    8 回复  |  直到 17 年前
        1
  •  39
  •   S.Lott    17 年前

    注意区别。

    设计 受契约驱动。契约驱动

    由测试驱动。测试驱动 发展 .

    在执行时是否放弃设计?你认为设计文件违反了规定吗?您是否分别维护合同和代码?

    软件是合同的一种实现方式。测试是另一回事。用户手册是第三本。操作指南是第四个。数据库备份/恢复过程是合同实施的一部分。

    开销 从合同设计开始。

    • 如果您已经在做设计,那么您可以将格式从过多的单词更改为只列出合同关系的正确单词。

    • 如果您不做设计,那么编写合同将消除问题,降低成本和复杂性。

    我看不出灵活性有任何损失。

    1. 从合同开始,

    2. A.编写测试和

    看看这两个开发活动是如何本质上相互交织的,它们都来自于合同。

        2
  •  27
  •   Jörg W Mittag    17 年前

    在TDD中,测试并不是真正的测试。它们是行为规范。然而,它们是 而且 queue.full? 而不是 queue.num_entries == queue.size .

    第二部分不能用合同代替。

    第一部分 可以 至少在单元测试中,可以用合同部分替代。TDD测试作为行为规范,对其他开发人员(单元测试)和领域专家(验收测试)都是如此。合同 而且 为其他开发人员、领域专家以及编译器和运行库指定行为。

    但是契约有固定的粒度:有方法前置和后置条件、对象不变量、模块契约等等。可能是循环变量和不变量。但是,单元测试测试行为的单元。这些方法可能比一个方法小,或者由多个方法组成。这不是你能用合同做的事。对于“大局”,您仍然需要集成测试、功能测试和验收测试。

    驾驶 您的开发过程:除非测试失败,否则您永远不会编写一行实现代码;除非测试全部通过,否则您永远不会编写一行测试代码;您只编写最少量的实现代码以使测试通过;您只编写最少量的测试代码以生成失败的测试。

    总之:使用测试来设计API的“流”和“感觉”。使用契约来设计API的契约。使用测试为开发过程提供“节奏”。

    大概是这样的:

    1. 为实现该特性一部分的单元编写单元测试
    2. 使用您在步骤2中设计的方法签名,编写方法原型
    3. 添加后置条件
    4. 实现方法体
    5. 如果验收测试通过,转到1,否则转到2

    Contract-Driven Design = Test-Driven Development - Writing Test Cases . 基本前提是契约提供了所有可能案例的抽象表示,而测试案例只测试特定案例。因此,可以从合同中自动生成合适的测试线束。

        3
  •  6
  •   Gray Gaffer    17 年前

    API是程序员的契约,UI定义是与客户机的契约,协议是客户机-服务器交互的契约。首先获得这些,然后您就可以利用并行开发轨道,而不会迷失在杂草中。是的,定期审查以确保满足要求,但在没有合同的情况下,不得开始新的轨道。“合同”是一个强有力的词:一旦部署,它就永远不能改变。您应该从一开始就包括版本管理和内省,对合同的更改仅通过扩展集实现,版本号随扩展集更改,然后您可以在处理混合或旧安装时进行适当的降级。

    我从一个大项目中艰难地学到了这个教训,这个项目进入了“永不着陆”,后来在公司生存、时间紧迫的情况下,我认真地运用了它。我们定义了协议,为事务的每一方定义并编写了一组协议模拟(基本上是罐装的消息生成器和接收的消息检查器,一个晚上的双脑编码),然后分别编写应用程序的服务器端和客户端。我们重新组合了当晚的演出,结果一切顺利。需求、设计、合同、测试、代码、集成。按这个顺序。重复上述步骤直到烤熟。

    我对TLA的设计有点怀疑。与模式一样,符合流行语的配方是一个很好的指南,但根据我的经验,没有一刀切的设计或项目管理过程。如果你严格按照手册(tm)办事,那么,除非它是一份符合国防部程序要求的国防部合同,否则你可能会在某个时候遇到麻烦。阅读这本书,是的,但一定要理解它们,然后还要考虑团队中的人。仅由本书强制执行的规则不会得到统一的强制执行-即使强制使用工具,也可能会有退出(例如,svn注释留空或神秘简短)。只有当工具链不仅强制执行程序,而且使其比任何可能的捷径更容易遵循时,程序才会被遵循。相信我,当事情变得艰难时,捷径就会被找到,你可能不知道凌晨3点使用的捷径,直到为时已晚。

        4
  •  2
  •   Evgeny    17 年前

    您还可以使用以合同的域语言编写的可执行验收测试。它可能不是实际的“契约”,而是单元测试和契约之间的一半。

    我会推荐使用Ruby Cumber http://github.com/aslakhellesoy/cucumber

    但既然您是一家Perl商店,那么也许您可以使用我自己在p5 Cumber上的一个小尝试。 http://github.com/kesor/p5-cucumber

        5
  •  1
  •   Ian Ringrose    17 年前

    video 有关概述,请参阅。

    如果 这是可行的,您的单元测试只需要为您尝试测试的每件事情编写一个示例,然后PEX将能够计算出哪些数据项会破坏测试。

        7
  •  0
  •   Raedwald    14 年前

    当您使用TDD实现一个新方法时,您需要一些输入:您需要知道检查测试的断言。契约式设计为您提供了这些断言:它们是方法的后置条件和不变量。

        8
  •  0
  •   Melvin Perez-Cedano    11 年前

    我发现DbC非常适合于跨接启动 循环,因为它有助于确定要开始的单元测试。我开始考虑使用DbC 先决条件 要进行TDD的对象必须处理,并且每个前置条件可能代表一个失败的单元测试,以启动红-绿重构周期。在某个时刻,我切换到以失败的单元测试开始循环 ,然后保持TDD流继续运行。我对TDD的新来者尝试过这种方法,它真的能启动TDD思维。

    总之,将DbC视为识别关键行为单元测试的有效方法。DbC有助于分析输入(前置条件)和输出(后置条件),这是我们编写可测试软件(TDD的一个类似目标)时需要控制(输入)和观察(输出)的两件事。

    推荐文章