如何在Swift中编写可测试的代码

时间:2016-08-23 15:56:36

标签: swift unit-testing functional-programming tdd design-guidelines

因此,当我开始对postNotificationaddObserver的简单2行进行单元测试时,我的这个问题就开始了。从这个类似的问题here你可以看到,为了使其可测试,你需要添加~20行& 部分远离编写代码的常用方法。

面对这个问题实际上是我第一次理解单元测试和TDD之间的区别。如果您的代码是可测试的,即如果您遵循TDD思维模式,则单元测试很容易。接下来我被问到如何编写可测试的代码,我没有找到太多的指导原则,每个教程只是跳到编写单元测试。 Apple拥有documentation对此毫无用处。

我最初的想法是,我需要针对“函数式编程”并以pure function方式编写我的函数。但是这又是非常耗时的,并且可能需要在现有代码中进行大量重构,甚至对于新项目需要大量添加的行,我甚至不确定是否that is the correct approach。是否有任何建议的指南或标准可以轻松编写可测试代码?

我自己已经了解的事情: 我知道你不应该编写任何代码,除非有测试失败,所以基本上我必须先编写测试,一旦出现错误,即使是编译器错误,我也要切换回来对于正在测试的实际类,编写任何必要的内容并使我的测试代码不会出现任何错误,然后切换回测试类并继续编写测试并修复编译错误,直到完成为止。然后运行测试,看看它是否检查我想要检查的内容。

对于所有测试,我应该确保我的测试会在我预期失败的地方准确传递和失败,即测试将在预期失败时通过。

我不知道的是如何以更简单的方式平滑过程。

我不是要求如何编写NSNotificationCenter的可测试代码,我要求编写可测试代码的一般指导原则。

1 个答案:

答案 0 :(得分:15)

这是一个相当大的问题,也是开发者的观点向不同方向发展的问题。同样重要的是要注意,使代码可测试是在很多基本方面,而不是Swift特定的问题:很多使你能够定期和方便地编写可测试代码的东西实际上依赖于你遵循一些基本的,普遍适用的原则。通常,测试驱动的设计实践可以间接地帮助您,通过验证您已经遵循通过测试合理执行代码的实践,同时为您带来其他程序员的生产力和可靠性优势。因此,遗憾的是,编写可测试代码不是学习使用Xcode的一些机械技巧的问题,而是通常证明您已经设计和规划了您编写的程序和库,并保留了一些良好实践。

我会尽力将下面的链接链接到一些Swift特定资源,以展示我倾向于遵循的更一般的原则,以使我的代码可以测试。

  1. 使代码可测试通常是遵循声音面向对象设计原则的副作用。

  2. 遵循健全的面向对象设计通常本身就是良好的更高层次的架构决策的副作用。基本上,请尽早思考并经常考虑您计划在程序的对象图中引入的类型。它们之间的角色和依赖关系是什么?从不同的上下文(例如,从UI代码到单元测试)执行代码时,对象图中的任何依赖项难以满足或正确构造吗?

    • 有许多关于建筑设计模式的计算机科学文献。 The Gang of Four仍然是阅读有关此主题的宝贵书籍(尽管并非所有这些都适用于您的典型Swift计划)。
    • 看看这个Swift design patterns演示,了解可以在Swift中实现多少常见设计模式的概述。
    • 特别是如果您的代码适用于移动应用,您应read about VIPER,面向移动应用的架构模式应用于iOS应用的典型架构需求。
    • 要将设计模式链接到上面列出的SOLID原则,“单一责任”原则可能是许多大型Cocoa程序中最明显违反的原则,这是由于糟糕的架构实践导致的,也导致很难测试代码。事实上,人们经常开玩笑地将MVC称为在Cocoa中实践中应用为"Massive View Controller"
  3. 以上提出的观点绝不是斯威夫特特有的,我希望不会有非常有争议的主张。然而,Swift还提供语言功能,这些功能也可以帮助您编写可靠的无错代码,部分原因是这些语言功能可以帮助您进行友好的代码测试。这里有一些很好的Swift实践:

    • Use value types when you can:Swift非常适合编写最小化自动引用计数引用(指针)的程序。这带来了性能优势,但也提高了编写可靠代码的机会,从而最大限度地减少了在测试中难以捕获的意外依赖性和数据竞争。
    • Keep things immutable when you can:Swift中的语法约定和类型系统可以帮助您避免可变状态,这会对代码的可测试性产生负面影响(配置对象图进行测试可能会变得困难,实现如果程序中可能存在的状态空间很大,则可以使用代码的真实可用测试覆盖率。
    • Apple还提供了一些关于the architectural matter of value types and immutability的指导,这些指南也涉及代码的可测试性。
    • 尽可能使用协议:了解原因,阅读the Liskov substitution principle :-)更严重的是,优先选择具体类型的协议可以帮助您编写可测试的代码,例如允许您在测试设置中实现依赖性使用测试特定类型伪造或模拟与测试无关的某些资源。
    • 使用函数式编程技术(当它有意义时):通常用函数编写功能可以帮助您编写可读,灵活的代码,避免可变状态。我建议Functional Swift by Chris Eidhof and others作为在Swift中应用函数模式的一个很好的指南。

    同样,这个问题很大,我真的只是在表达我的答案,以便指出没有单一的灵丹妙药可测试性 - 这是你通过遵循许多最佳实践而实现的结果设计你的代码。