我想让一个非常大的,非常遗留的项目 能够测试。
我们有许多静态的可用服务, 我们的代码大多使用。 问题在于这些是很难嘲笑的。 它们过去是单质的。 现在它们是假单质的, 相同的静态界面, 但功能代表到一个可以被切换的实例对象。 例如 :
class ServiceEveryoneNeeds
{
public static IImplementation _implementation = new RealImplementation();
public IEnumerable<FooBar> GetAllTheThings() { return _implementation.GetAllTheThings(); }
}
现在在我的单位测试中:
void MyTest()
{
ServiceEveryoneNeeds._implementation = new MockImplementation();
}
目前为止,很好。在测试中,我们只需要一个执行。但测试平行进行,可能需要不同的模型,所以我做了:
class Dependencies
{
//set this in prod to the real impl
public static IImplementation _realImplementation;
//unit tests set these
[ThreadStatic]
public static IImplementation _mock;
public static IImplementation TheImplementation
{ get {return _realImplementation ?? _mock; } }
public static void Cleanup() { _mock = null; }
}
然后:
class ServiceEveryoneNeeds
{
static IImplementation GetImpl() { return Dependencies.TheImplementation; }
public static IEnumerable<FooBar> GetAllTheThings() {return GetImpl().GetAllTheThings(); }
}
//and
void MyTest()
{
Dependencies._mock = new BestMockEver();
//test
Dependencies.Cleanup();
}
我们选择了这条路线,因为它是一个庞大的工程,将这些服务注入每一个需要的阶层。 与此同时,这些是大多数功能都依赖的我们代码库中的普遍服务。
我理解,这种模式是坏的,因为它掩盖了依赖性,而不是建筑师注入,而建筑师注入明确表明依赖性。
However the benefits are:
- we can start unit testing immediately, vs doing a 3 month refactor and then unit testing.
- we still have globals, but this appears to be strictly better than where we were.
虽然我们的依存关系仍然隐含着,但我想说,这一办法绝对比我们的做法好。 除了隐藏的依附关系之外,这是否比使用适当的DI集装箱还要糟糕? 我将遇到什么问题?