我读到单身人士对可测试性不利.你能详细说明吗?单身人士不能被嘲笑吗?他们写作是由于紧耦合,但我看不出为什么.
这取决于你如何使用单例以及该单例是否实现了一个接口.如果它是一个单例的事实是一个实现细节,那么这可能没关系.如果您在要测试的代码中使用其单例性质,则更多的是问题.
以我的Noda Time项目为例.它有一个IClock
界面代表"获取当前时间的方式".这有一个叫做SystemClock
singleton的实现.现在考虑使用它的一些代码:
public class BadClass { public bool IsIt2016Yet() { var now = SystemClock.Instance.Now; return now.InUtc().Year >= 2016; } }
我们无法在不改变SystemClock.Instance
它的情况下测试该代码.该代码与单例类紧密耦合.但是,考虑一下:
public class GoodClass { private readonly IClock clock; public GoodClass(IClock clock) { this.clock = clock; } public bool IsIt2016Yet() { var now = clock.Now; return now.InUtc().Year >= 2016; } }
现在你很好 - 在你的生产代码中你设置依赖注入以便SystemClock.Instance
在任何你想要的地方使用IClock
,但在测试代码中你可以使用假时钟 - 比如NodaTime.Testing
包中提供的那个.在生产中,代码最终将使用单例,但它并没有与它紧密耦合.
当然,假设您已经适当地设置了依赖注入.如果你想在任何地方构建一个实例而不关心它需要一个时钟的事实,你可以选择一个选项,它可以选择将类连接到SystemClock
单例:
public GoodClass(IClock clock) { this.clock = clock; } public GoodClass() : this(SystemClock.Instance) { }
现在它仍然是可测试的(并且通常是灵活的)因为你可以传入时钟,但它很方便,因为它有效地"默认"到系统时钟.(您可以使用可选参数执行此操作,并null
使用最终SystemClock.Instance
作为另一种选择的参数.)