Ian Cooper 在他的演讲TDD中,哪里都出错了,将Kent Beck的初衷推到了TDD中的单元测试(测试行为,而不是具体的类方法),并主张避免将测试与实现耦合。
对于行为,例如save X to some data source
在具有一组典型的服务和存储库的系统中,我们如何通过存储库对服务级别的某些数据的保存进行单元测试,而又不将测试与实现细节耦合(例如调用特定方法) )?避免这种耦合实际上不值得付出某种努力/坏处吗?
Ian Cooper 在他的演讲TDD中,哪里都出错了,将Kent Beck的初衷推到了TDD中的单元测试(测试行为,而不是具体的类方法),并主张避免将测试与实现耦合。
对于行为,例如save X to some data source
在具有一组典型的服务和存储库的系统中,我们如何通过存储库对服务级别的某些数据的保存进行单元测试,而又不将测试与实现细节耦合(例如调用特定方法) )?避免这种耦合实际上不值得付出某种努力/坏处吗?
Answers:
您的特定示例是一种情况,您通常必须通过检查是否调用了某种方法来进行测试,因为这saving X to data source
意味着要与外部依赖项进行通信,因此您必须测试的行为是通信按预期进行。
但是,这不是一件坏事。应用程序及其外部依赖项之间的边界接口不是实现细节,实际上,它们是在系统体系结构中定义的;这意味着这种边界不太可能改变(或者,如果必须改变,那将是最不频繁的改变)。因此,将测试耦合到repository
接口上不会给您带来太多麻烦(如果确实如此,请考虑接口是否没有从应用程序中窃取责任)。
现在,仅考虑与UI,数据库和其他外部服务分离的应用程序的业务规则。这是您必须自由更改代码的结构和行为的情况。在这里,耦合测试和实现细节将迫使您更改比生产代码更多的测试代码,即使应用程序的整体行为没有变化。这是测试State
而不是Interaction
帮助我们更快进行的地方。
PS:我并不是要说通过国家或互动进行测试是否是TDD的唯一真实方法-我认为这是使用正确的工具完成正确的工作的问题。
我对该演讲的解释是:
谈话中没有提到,但是我认为建议的假定上下文是这样的:
因此,测试组件是最大的可能范围,在此范围内仍可以合理地将某些内容称为单元测试。这与某些人(尤其是学者)使用该术语的方式完全不同。它与典型的单元测试工具教程中的示例不同。但是,它确实与硬件测试中的起源相匹配。电路板和模块均经过单元测试,而不是电线和螺钉。或者至少您不制造模拟波音来测试螺丝...
从中推论出自己的想法,
如果您正确且干净地执行此操作,则几乎不需要模拟工具;每个系统只使用几次。
数据库通常是协作者,因此它是伪造的而不是被嘲笑的。手工实施会很痛苦;幸运的是,这样的事情已经存在。
基本的测试模式是执行某些操作序列(例如,保存和重新加载文档);确认它有效。这与任何其他测试方案相同;没有(有效的)实现更改很可能导致此类测试失败。
例外情况是被测试系统写入但从未读取过数据库记录;例如审核日志或类似内容。这些是输出,因此应该嘲笑。测试模式是按一定顺序进行的操作;确认使用指定的方法和参数调用了审核接口。
请注意,即使在这里,只要您使用的是诸如Simito之类的类型安全的模拟工具,重命名接口方法都不会导致测试失败。如果使用加载了测试的IDE,它将与方法重命名一起进行重构。如果您不这样做,则测试将无法编译。