我不明白我是如何使用单元测试进行测试的。
简短的回答:你正在测试逻辑,而忽略了 副作用 。
你没有测试 一切 ;但你正在测试一些事情。
此外,如果你记住你不是 真 测试具有副作用的代码,然后你有动力安排你的代码,以便实际依赖副作用的部分很小。大件实际上并不关心数据的来源,这些都很容易测试。
所以“某事”可以是“大多数事情”。
那里 是 阻抗问题 - 如果你的测试加倍模拟生产原件,那么你的一些测试结果将是不准确的。
我的理念是尽可能少地测试以达到给定的置信水平 肯特贝克,2008年
我的理念是尽可能少地测试以达到给定的置信水平
肯特贝克,2008年
想象“尽可能少”的一种方式是考虑成本 - 我们的目标是给定一定的置信水平,所以我们希望尽可能多地获得信心,因为我们可以使用廉价的单元测试,然后制作与更昂贵的技术差异化。
Cory Benfield的演讲 以正确的方式构建协议库 描述了我们在这里讨论的那种分离的例子。如何解析HTTP消息的逻辑与读取字节的问题是分开的。如果你使复杂的部分易于测试,并且难以测试的部分太简单而不能失败,那么你成功的机会就相当不错了。
我认为您的关注是有效的。对我来说,TDD更像是一种进化设计实践,而不是单元测试实践,但我会将其保存为另一个讨论。
在您的示例中,我们真正测试的是您的各个类中包含的逻辑是合理的。通过存根来自数据库的数据,您可以确保您的代码适用于该特定方案。这使得确保所有数据方案的完整测试覆盖变得更加容易。你是对的,这确实没有 测试 整个系统端到端,但重点是降低整体测试维护成本并加快反馈速度。
我的方法是在单元测试级别模拟大多数协作者,然后在集成测试级别编写验收测试,使用实际数据验证您的系统。因为使用模拟数据的单元测试允许您测试各种数据场景,所以您只需要使用集成测试来测试其中一些场景,以确保您的代码能够按预期执行。
您可以单独针对实际数据库测试代码。只需为每个测试创建新的数据库实例,或者一个接一个地同步执行测试,并在下一次测试之前清理数据库。
但是使用实际数据库会使测试变慢,这会减慢您的工作速度,因为您需要快速反馈您正在做的事情。
不要测试每个类 - 测试主要特征逻辑,它可以使用许多不同的类和mock / stub只依赖,这使得测试变慢。
找到您的应用程序边界并在它们之间测试逻辑而不用嘲笑 例如,在简单的web api应用程序中,边界可以是: - 控制器动作 - >请求(输入) - 控制器动作 - >响应(输出) - 数据库 - >收到请求的副作用。
假设我们生活在完美的世界中,新的数据库和Web服务器设置将需要几毫秒。然后,您将测试应用程序的整个管道: 1.配置数据库以进行测试 2.向web api服务器发送请求 3.断言响应包含预期数据 4.断言数据库状态按预期更改
但在现在世界,你的界限将是控制器动作和抽象的数据库访问点。这使您的测试如下所示: 1.配置模拟数据库访问点(存储库) 2.使用给定参数调用控制器操作 3.断言该操作返回预期结果 4.可能断言模拟的存储库收到了预期的更新参数。
如果您的应用程序没有逻辑,只需从数据库读取/更新数据 - 使用实际数据库进行测试,或者,如果您的数据库框架允许,则使用数据库内存。