【发布时间】:2015-07-26 15:01:39
【问题描述】:
在开发 TDD 时,您的对象会随着代码的发展而“增长”。首先它们只包含一些功能,然后您添加新功能。您基本上可以通过组合和/或继承来做到这一点。
同时,您几乎总是使用接口(用于测试和生产代码)来确保低耦合、依赖倒置、依赖注入和模拟。
你如何管理这个?
我的意思是,例如:您创建了一个类,现在它必须包含一个新属性(例如,一个 Person 现在可以有一个电子邮件)。怎么办?
- 修改类,添加新属性: 然后你必须添加新的构造函数。但是,如果您修改现有的构造函数,那么您必须重构所有涉及的 TEST,而不仅仅是生产代码。您可以尝试在添加新属性时保留所有构造函数,但最后大多变得无用、过时(仅由于 TESTS 而存在),具有“构造函数调用另一个构造函数”的复杂逻辑(或使用某种“工厂” )
- 派生类:这更符合 OCP。但是,如果您通过小步骤创建一个真正的 TDD,如果您总是从一个非常简单的类开始派生,那么您将以极其复杂且不知何故不必要的继承结束。此外,假设您必须始终只测试 PUBLIC 暴露成员。因此,同样,随着基类受到保护,必须重构测试以访问公共测试。
- Compose: Compose 对构造函数没有问题,但并不总是一个好的解决方案。至于我们当前的示例。
在某种程度上,接口也会发生类似的事情。
因此,随着代码的增长,构造函数和接口必须不断发展。我心中有三个戒律:
- 您应该避免重构测试。
- 生产代码不得保留“仅用于测试的代码”(即构造函数)
- ISP 声明使用特定接口。随着代码的增长,其中许多变得不必要,因为它们仅用于测试(即模拟)在许多情况下应受保护或私有的类。
所以,正如我所说...我在开发 TDD 时如何管理这一切?我知道这是一个很长的问题,所以,如果你能参考一些好的文章或资源
【问题讨论】:
标签: inheritance interface constructor tdd composition