代码之家  ›  专栏  ›  技术社区  ›  Burt

单元测试采用[已结束]

  •  70
  • Burt  · 技术社区  · 16 年前

    我们有一个抽象基类用于单元测试我们的控制器,它充当调用子类抽象方法实现的模板,即框架调用Initialize,因此我们的控制器类都有自己的Initialize方法。

    19 回复  |  直到 13 年前
        1
  •  109
  •   Keithius    10 年前

    提示:

    避免编写过程代码

    如果你用OO语言编写代码, use OO constructs

    • 尽可能避免全球状态。
    • 避免静态,因为它们往往会在你的代码库中产生涟漪,最终导致不应该是静态的东西。它们还会使你的测试环境膨胀(见下文)。
    • 有效利用多态性预防 excessive ifs and flags

    找出变化,封装它,并将其与保持不变的东西分开。

    代码中的瓶颈比其他部分变化更频繁。在你的代码库中这样做,你的测试就会变得更加健康。

    • 重构和模块化。
    • 保持测试规模小、重点突出。

    围绕测试的上下文越大,维护起来就越困难。

    • 它们允许您通过为测试生命周期提供更细粒度的挂钩来消除测试中的重复。
    • 调查使用测试双精度(模拟、伪造、存根)来减小测试上下文的大小。
    • Test Data Builder 图案。

    从测试中删除重复,但要确保它们保持重点。

    "Evil Unit Tests"

    • 如果没有人能弄清楚它在做什么,他们就不会想修复一个测试。
    • 每个测试只使用一个断言。

    在正确的级别进行测试,以验证您想要验证的内容。

    • 将依赖关系彼此隔离。
    • 使用依赖注入/控制反转。
    • 使用test double来初始化一个对象进行测试,并确保您正在单独测试单个代码单元。
    • 确保你正在编写相关的测试
      • 通过故意引入一个bug并确保它被测试捕获来“跳出陷阱”。
    • 另请参见: Integration Tests Are A Scam

    知道何时使用基于状态的测试与基于交互的测试

    真正的单元测试需要真正的隔离。单元测试不会访问数据库或打开套接字。别再嘲笑这些互动了。验证您与合作者的对话是否正确,而不是此方法调用的正确结果是“42”。

    演示试驾代码

    一个给定的团队是否会对所有代码进行测试驱动,或者为每一行代码编写“先测试”,这还有待商榷。但他们是否应该至少先编写一些测试?当然。在某些情况下,测试优先无疑是解决问题的最佳方式。

        2
  •  19
  •   cjk    16 年前

    你在测试足够小的代码单元吗?除非你从根本上改变了核心代码中的所有内容,否则你不应该看到太多的变化。

    一旦事情稳定下来,你会更加欣赏单元测试,但即使是现在,你的测试也在突出框架变化的传播程度。

        3
  •  12
  •   Mark Simpson    16 年前

    没有更多的信息,很难很好地了解你为什么会遇到这些问题。有时,更改界面等不可避免地会破坏很多东西,其他时候则归结为设计问题。

    尝试对你看到的失败进行分类是个好主意。你遇到了什么样的问题?例如,测试维护(如在重构后使其编译!)是由于API的更改,还是由于API的行为更改?如果你能看到一个模式,那么你可以尝试更改生产代码的设计,或者更好地保护测试不受更改。

    如果更改一些东西会在许多地方对你的测试套件造成难以估量的破坏,你可以做一些事情(其中大多数只是常见的单元测试技巧):

    • 小代码单元。提取 接口或基类 里面有“接缝”。越多 您必须引入的依赖项(或 使用“新”),越容易受到 将更改您的代码。如果每个 代码单元有几个 依赖关系(有时是一对或 完全没有)那就更好了 与变化隔绝。

    • 只对测试内容进行断言 需要。不要断言中间, 偶然或无关的状态。设计: 合同和合同测试(例如。 如果你正在测试堆栈弹出方法, 之后不要测试count属性 推——这应该是在一个 单独测试)。

      我看到了这个问题 相当多,尤其是每次测试 是一种变体。如果有 偶然的状态变化,它就会破裂 上面断言的一切 (是否需要断言或 不是)。

    • 就像使用普通代码一样,使用工厂和构建器 需要在API更改后更新构造函数调用。..

    • 门第一。你的测试应该始终 如果可用,请使用正常状态。仅在必要时使用基于交互的测试(即没有状态可供验证)。

    不管怎样,这句话的要点是,我会试图找出测试失败的原因/位置,并从那里开始。尽最大努力让自己免受变化的影响。

        4
  •  8
  •   Jon B    16 年前

    单元测试的好处之一是,当你做出这样的更改时,你可以证明你没有破坏你的代码。你确实必须让你的测试与你的框架保持同步,但这项相当平凡的工作比试图找出重构时发生了什么要容易得多。

        5
  •  4
  •   Sourabh    16 年前

    我会坚持你坚持TDD。 试着检查你的单元测试框架,与你的团队一起做一个RCA(根本原因分析),并确定该领域。

    如果您能很好地分享您的案例研究,我们将不胜感激,然后我们可以在问题领域挖掘更多信息?

        6
  •  4
  •   azheglov    16 年前

    好问题!

    设计好的单元测试和设计软件本身一样困难。开发人员很少承认这一点,因此结果往往是匆忙编写的单元测试,每当被测系统发生变化时都需要维护。因此,解决问题的一部分可能是花更多的时间来改进单元测试的设计。

    我可以推荐一本值得称赞的好书 The Design Patterns of Unit-Testing

    希望这能帮到你

        7
  •  4
  •   Robert Gowland    16 年前

    如果问题是你的测试与实际代码不符,你可以做以下一项或两项:

    1. 培训所有开发人员不要通过不更新单元测试的代码审查。
        8
  •  3
  •   CSharpAtl    16 年前

    好吧,如果代码中的逻辑发生了变化,并且您已经为这些代码编写了测试,我认为需要更改测试来检查新的逻辑。单元测试应该是测试代码逻辑的相当简单的代码。

        9
  •  3
  •   David Yancey    16 年前

    你的单元测试正在做它们应该做的事情。把由于框架、即时代码或其他外部源的变化而导致的任何行为中断暴露出来。这应该做的是帮助您确定行为是否发生了变化,单元测试是否需要相应地修改,或者是否引入了错误,从而导致单元测试失败并需要纠正。

        10
  •  2
  •   Kyle Krull    16 年前

    我不确定是什么具体问题导致难以维护代码的测试,但我可以分享一些我自己在测试失败时遇到类似问题的经历。我最终了解到,缺乏可测试性主要是由于被测类的一些设计问题:

    • 使用单体
    • 调用大量静态方法进行业务逻辑和数据访问,而不是接口方法

    因此,我发现我的测试通常会中断——不是因为被测类的变化,而是因为被测类时调用的其他类的变化。一般来说,重构类以要求它们的数据依赖关系,并使用模拟对象进行测试(EasyMock等人,Java)使测试更加集中和可维护。我真的很喜欢一些关于这个主题的网站:

        11
  •  2
  •   SingleNegationElimination    16 年前

    为什么每次更改框架时都必须更改单元测试? 难道不应该反过来吗?

    如果你在使用TDD,那么你应该首先确定你的测试是在测试错误的行为,而应该验证所需的行为是否存在。现在你已经修复了你的测试,你的测试失败了,你必须把框架中的bug挤进去,直到你的测试再次通过。

        12
  •  1
  •   Gerrie Schenck    16 年前

    当然,一切都有代价。在开发的早期阶段,必须更改许多单元测试是很正常的。

    您可能想检查代码的一些部分,以进行更多的封装、创建更少的依赖关系等。

    当你接近生产日期时,你会很高兴你有这些测试,相信我:)

        13
  •  1
  •   philant    16 年前

    你的单元测试不是太黑盒化了吗?我是说。..让我举一个例子:假设你正在对某种容器进行单元测试,你是使用容器的get()方法来验证一个新项目是否实际存储,还是设法获得一个实际存储的句柄,直接在存储的地方检索该项目?后者使测试变得脆弱:当你更改实现时,你正在破坏测试。

    您应该针对接口而不是内部实现进行测试。

    当你更改框架时,最好先尝试更改测试,然后再更改框架。

        14
  •  1
  •   Boris Kleynbok    16 年前

    我建议投资一个测试自动化工具。如果你使用的是持续集成,你可以让它协同工作。有一些工具可以扫描你的代码库,并为你生成测试。然后将运行它们。这种方法的缺点是它过于通用。因为在许多情况下,单元测试的目的是破坏系统。

    自动化工具有一条细线,你可以定义它有更好的代码覆盖率。

    然而,使用编写良好的基于开发人员的测试,您也将测试系统完整性。

    希望这能有所帮助。

        15
  •  1
  •   sal    16 年前

    如果你的代码真的很难测试,并且测试代码中断或需要付出很多努力来保持同步,那么你就有一个更大的问题。

        16
  •  1
  •   Norman Ramsey    16 年前

    额外的代码似乎已经成为一个维护难题,因为当我们的内部框架发生变化时,我们必须四处修复任何挂起它的单元测试。

    您可以尝试重构您的框架,使其由可以独立测试的较小部分组成。然后,当你的框架发生变化时,你希望(a)改变的部分更少,或者(b)改变的主要是组成部分的方式。无论哪种方式,都会让你更好地重用代码和测试。但这需要真正的智力努力;不要指望这很容易。

        17
  •  1
  •   Andriy Volkov    16 年前

    我的观点是,许多新颖的软件开发技术只有在一起使用时才能发挥作用。特别是MVC、ORM、IoC、单元测试和模拟。DDD(在现代原始意义上)和TDD/BDD更独立,因此您可以使用或不使用它们。

        18
  •  0
  •   Dale K    16 年前

        19
  •  0
  •   Anon    16 年前

    我一直在思考这个话题。我非常认同单元测试的价值,但并不认同严格的TDD。在我看来,在某种程度上,你可能正在进行探索性编程,你将事物划分为类/接口的方式需要改变。如果你在旧类结构的单元测试上投入了大量时间,那么对重构的惯性就会增加,丢弃额外的代码会很痛苦,等等。

    推荐文章