【问题标题】:When not / to write tests before implementation? [closed]何时不/在实施之前编写测试? [关闭]
【发布时间】:2008-11-26 01:38:49
【问题描述】:

我不确定“先测试”是如何工作的,我想听听关于何时以及为何采用这种方法的争论。

我听说通常建议在编写单行实现之前编写测试和模拟事物。但是,我不禁认为它并不适合所有情况。 例如,假设我正在制作一个原型,但我还不确定一切将如何工作。所以我只是开始寻找我认为我需要的每个步骤的示例并将它们放入我的代码中。最后,我证明了我的理论,并没有花那么长时间。这本质上是“我的测试”。这不是单元测试,而是测试(很可能是控制台应用)。

这就是我的工作方式。我想我想做什么并尝试去做。如果它有效,那么我最终会回去编写单元测试,以便我可以捕获回归。这与您“应该做的”不同吗?

【问题讨论】:

    标签: unit-testing testing automated-tests methodology


    【解决方案1】:

    最重要的规则是:先做最危险的事情。

    首先进行测试用例隐含地认为编码中风险最大的部分是对正在创建的对象的接口和行为的错误沟通和误解。

    对于许多项目来说,这很可能是正确的,TDD 在这些情况下非常合适。

    但是,在许多项目中并非如此,在这些情况下应用 TDD 是一个糟糕的选择。

    如果您的最大风险是可用性,请停止使用单元测试并进行一些 UI 原型设计。

    如果你最大的风险是性能,先做一些性能原型,不要担心接口。

    这个列表还在继续。

    先做有风险的事情有很多好处:

    • 在许多资源被浪费之前,不可避免地注定要失败的项目早早夭折。

    • 遇到麻烦但可以挽救的项目尽早获得项目管理的关注,当它可以做一些好事时。

    • 当项目失败的风险较低时,您组织的业务部门会对其重视程度更高;不必要地提前取消的可能性较小。

    【讨论】:

      【解决方案2】:

      “我听说经常建议在编写单行实现之前编写测试和模拟事物……我最终回去编写单元测试……这与你“应该做的事情”不同吗“?”

      既然你是从自己的问题的答案开始的,那么你并不是真的在问这个问题,是吗?

      人们有很多原因 回答他们自己的问题。 有时,这是一种争论的方式。
      它允许人们说“我不是在争论,我是 只是问为什么这是错误的”。


      目标是先测试。以下是它的工作原理。

      假设我正在制作一个原型,但我还不确定一切将如何运作。

      不过,我确实知道一件事。它应该做什么。

      1. 写下它应该做什么的具体例子。具体的、特定的输入和输出。

      2. 这就是测试用例。我先做了。我可以将其正式化为单元测试吗?可能不是。但是,我从一个验收测试用例开始。

      现在,我可以将问题分解为多个部分。

      1. 所以我开始寻找我认为需要的每个步骤的示例。

      2. 对于我认为我需要的每个示例,我都会写下步骤中的内容和结果。

      3. 这些是测试用例。我先做了。在许多情况下,我可以将它们形式化为单元测试。

      4. 完成测试后,我会返回每个步骤的示例并将其放入我的代码中。

      我做了测试,然后是编码。在进行任何编码之前,我没有进行所有测试。我首先进行了测试,但不是以一种疯狂的全测试无代码方式。我以增量测试-一点-代码-一点的方式做到了。但一切都是先测试的。

      【讨论】:

        【解决方案3】:

        这很简单,答案是在原型制作期间。在这个阶段,您对您构建的系统还不够了解,无法正确测试,无论如何,良好的实践表明原型代码应该是一次性代码,因此在这个阶段测试不会给您带来任何真正的好处。但是,从原型设计中获得的理解将对您有所帮助,这样您就可以在投入生产后进行有效的测试。

        所以是的,如果您在原型之后进行测试,那么您的方法是正确的

        【讨论】:

        • 人们也可能会争辩说,原型设计是实现的一部分,因此只有在您已经拥有一些简单的 API 来运行基本测试时才应该这样做。这样,您首先要了解您希望如何使用您的系统,这是 TDD 的优势之一。
        • 是的,我同意你的观点,并且也使用这种方法,但我说的是 API 设计之下的原型设计,例如当你试图弄清楚你需要什么类型的组件和系统时(因为这个问题以前没有得到解决,或者你正在尝试一种全新的方法)。
        • 我想在某些情况下,您绝对需要能够轻松地进行调整,而无需进行早期单元测试的障碍。我承认经常这样做,但总是觉得我懒得不坐下来提前考虑我的 API。
        【解决方案4】:

        我认为您不测试尖峰/原型的方法很好。但有两个想法:

        1. 一旦你完成了你的原型并且你知道你要做什么,要么把它扔掉然后重新实现它先测试,或者为你已经编写的代码编写测试。

        2. 当您有更多的单元测试练习时,您可能会发现在测试中创建原型比创建控制台应用程序更快。我不是说创建一个测试和一个单独的类,我的意思是在测试方法中探索 w/code。我已经做过很多次了,我对此非常满意。当我学习新的 api 甚至新语言时,测试给了我最快的反馈周期来尝试实验。然后,一旦代码正常工作,我就可以将其提取到单独的方法/类中,成为真实系统的一部分。

        【讨论】:

          【解决方案5】:

          即使您正在编写一个废弃的原型,考虑原型实际上会做什么,并从确认它可以做的测试开始,这仍然是有用的。确保可以测试原型也将塑造解决方案的方式。

          那么当代码被丢弃时,你仍然有测试。

          我在开始测试原型时也遇到了麻烦,但当我设法做到这一点时,我总是很高兴我做到了。

          【讨论】:

            【解决方案6】:

            我发现,当我仍在构建代码的“故事”时,首先编写测试并不能很好地发挥作用。当我不确定接口是什么样子时,很难编写测试。我可能会编写存根代码来充实类和接口而不考虑测试。但我试图尽快进行测试。我发现如果我在构建设计时记下要测试的东西会很有帮助,然后当我的设计更加稳固时,我会回到我的笔记并首先进行这些测试。这通常意味着实现代码和单元测试代码一起增长,两者都不是在另一个之前。

            【讨论】:

              【解决方案7】:

              没有单一的“正确的方法”。但是,我确实认为测试驱动开发 (TDD) 会对您的情况有所帮助。我发现首先编写测试有助于塑造 API 并使代码更简洁。当您首先编写测试时,您首先会考虑如何调用代码(接口,或“这应该做什么”),然后再考虑实现(“我应该怎么做”)。

              例如,想象一下创建一个 CRM 模块。您可能会认为首先要做的是吸引花费最多钱的客户。所以,你会写一个测试:

              Assert.AreEqual(Customer1, crm.GetMostValuableCustomer(), "最有价值的客户不符合预期");

              然后您可能会遵循以下内容:

              Assert.AreEqual(new Customer[] {Customer1, Customer2, Customer3}, crm.GetCustomerByValue(), "GetCustomersByValue() 不符合预期");

              所以,关键是您从不同的角度考虑代码(作为消费者,而不是作为生产者)。我相信可以帮助我编写更简洁的代码,并且我不必稍后再返回并创建回归测试。我希望我有一个更好的示例,但希望您能看到使用这种方法实际上如何在原型设计阶段为您提供帮助。

              【讨论】:

                猜你喜欢
                • 2010-09-28
                • 2014-01-13
                • 1970-01-01
                • 2010-09-08
                • 1970-01-01
                • 2011-01-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多