当为一个简单的Rails应用程序编写规范时,以下是完整测试覆盖的正确方法吗?
- 为所有用户故事编写功能规范
- 写入控制器规格,以确保单个动作响应正确,并设置了所有必需的变量
- 编写模型规范以确保所有方法,验证等。正在按预期工作
- 写邮件规格
- 写入路由规范
这是足够的,太多了(例如,如果我写了功能规范,我可以跳过一些较低级别的规范吗),还是不够?为什么?
您不需要为每个层中的每个对象编写规范,要么获得100%的测试覆盖率,要么测试驱动(要求您实现)应用程序中的所有重要行为。相反,正如行为驱动开发(BDD)建议的那样,编写由外而内的规范,并且只在必要时编写较低级别的规范。
测试完整性的最重要度量是需求覆盖率:它对每个用户场景,以及每个需要新代码的场景的每个细节,至少在一个测试中表示是有帮助的。如果您遵循典型的敏捷实践(提到用户故事表明您是这样做的),那么您的测试可能是您记录需求的唯一地方,因此您可能无法对这种覆盖率给出数字。加上
也很有帮助- 行覆盖率(大多数人所说的测试覆盖率),意味着每一行代码至少被一个测试执行,并且
- 集成覆盖率,意味着从一个类到另一个类的每个方法调用至少由一个测试执行。
对于每个故事,
- 只写将测试驱动所有故事的独特快乐路径的功能规格。
- 编写额外的功能规范,以确保集成覆盖架构上有趣的快乐路径和悲伤路径的小变化。例如,我经常为一个涉及表单的故事编写三个功能规范:一个是用户填写所有可能的字段并成功,另一个是用户填写尽可能少的信息但仍然成功(确保未指定的值和默认值按预期工作),另一个是用户犯了错误,失败,纠正错误并成功。
此时,你已经测试驱动了每一层(控制器、模型、视图、帮助器、邮件器等),只有特性规范。
编写模型和助手规范,以排除完全存在于这些类中的详细需求。例如,一旦您编写了一个add -path特性规范,该规范确定输入一个特定的无效属性会将用户发送回编辑他们的表单提交并显示一条消息,那么您就可以通过在该模型规范中编写更多的示例来完全处理其他无效属性,以测试模型属性是否被验证,并让您已经测试驱动的体系结构将错误传播回用户。
注意,尽管你的功能规格已经测试了快乐的路径通过模型和辅助方法,一旦你开始写例子为小法或错误情况下,你可能会想写与成功的例子或例子的方法,所以你可以看到整个方法的描述在一个地方,所以你可以通过运行所有的测试方法充分的例子,而不是还需要运行任何功能规格。
你可能根本不需要某些规格:
- 精心设计的控制器动作很短,很少或没有条件,所以你通常根本不需要任何控制器规格。只在需要的时候编写它们,并存根模型,邮件等行为,以保持它们简单和快速。
- 同样,视图和邮件应该有很少或没有条件(复杂的代码应该重构成helper和模型方法),所以你通常根本不需要视图或邮件规范。
- 你的功能规格将测试驱动所有你需要的路由,所以你可能不需要路由规格。我只在从一个主要的Rails版本升级到下一个主要版本时,不得不对路由进行重大重构时才使用过路由规范。
只要你总是在写新代码之前写一个测试,你就总是有100%的行覆盖率。
这个测试策略听起来真的很全面。如果您有所有这些测试,您将有很好的测试覆盖率。然而,它将花费您更长的时间来交付您的项目。作为一个只做有限测试的人,你也不会敏捷。测试必须适合项目。不要过度测试。过度测试会耗费时间和金钱。不要被测试。
做单元测试有正确的方法。有一些正确的方法可以进行集成测试。手套必须合适。如果您的应用程序主要面向前端,那么最好从集成测试开始。如果你正在编写一个后端应用程序或API,那么单元测试可能是一个更好的起点。我认为从一种风格的测试开始,然后扩展到不同的风格,这比尝试测试应用程序的每一层要好。
为什么不从简单的单元测试开始?它们很容易写。编写这些测试,然后跟踪您发布了多少bug。你是不是让太多虫子进来了?你有很多退化问题吗?是否存在正在进入生产的bug,而您的套件没有发现?如果答案是肯定的,那么也许是时候编写一些更高级别的测试了。记住,测试级别越高,开发成本就越高。
如果你没有发布bug,那么你就没有理由编写更多的测试。记住这里的最终目标。我们希望发布无bug的代码。如果我们可以编写一个测试,并且只编写一个测试,就可以确保我们这样做,那么就没有理由进行进一步的测试。