【发布时间】:2011-12-20 15:50:07
【问题描述】:
我一直在阅读Factory 模式,并且看到一些文章建议将工厂模式与依赖注入结合使用,以最大限度地提高可重用性和可测试性。虽然我还没有找到这种 Factory-DI 混合的具体示例,但我将尝试并给出一些我的解释的代码示例。但是,我的问题实际上是关于这种方法如何提高可测试性。
我的解释:
所以我们有一个Widget 类:
public class Widget {
// blah
}
我们想要包含一个WidgetFactory 来控制Widgets 的构造:
public interface WidgetFactory {
public abstract static Widget getWidget();
}
public class StandardWidgetFactory implements WidgetFactory {
@Override
public final static Widget getWidget() {
// Creates normal Widgets
}
}
public class TestWidgetFactory implements WidgetFactory {
@Override
public final static Widget getWidget() {
// Creates test/mock Widgets for unit testing purposes
}
}
虽然这个例子使用了 Spring DI(这是我唯一使用过的 API),但我们谈论的是 Guice 还是任何其他 IoC 框架并不重要;这里的想法是,我们现在要在运行时注入正确的WidgetFactory 实现,这取决于我们是在测试代码还是正常运行。在 Spring 中,bean 配置可能如下所示:
<bean id="widget-factory" class="org.me.myproject.StandardWidgetFactory"/>
<bean id="test-widget-factory" class="org.me.myproject.TestWidgetFactory"/>
<bean id="injected-factory" ref="${valueWillBeStdOrTestDependingOnEnvProp}"/>
然后,在代码中:
WidgetFactory wf = applicationContext.getBean("injected-factory");
Widget w = wf.getWidget();
这样,一个环境(部署级)变量(可能在某处的 .properties 文件中定义)决定 Spring DI 是注入 StandardWidgetFactory 还是 TestWidgetFactory。
我做得对吗?!? 这似乎是很多基础设施为我的Widget 获得了良好的可测试性。并不是说我反对它,但对我来说,这就像过度设计。
我的挂断:
我之所以问这个问题是因为我将在其他包中拥有其他对象,这些包中有使用 Widget 对象的方法。也许是这样的:
public class Fizz {
public void doSomething() {
WidgetFactory wf = applicationContext.getBean("injected-factory");
Widget widget = wf.getWidget();
int foo = widget.calculatePremable(this.rippleFactor);
doSomethingElse(foo);
}
}
如果没有这个庞大的、看似过度设计的设置,我将无法将“模拟Widgets”注入到我的Fizz::doSomething() 单元测试中。
所以我很伤心:一方面,我觉得我在想太多事情——我很可能正在做这件事(如果我的解释不正确)。另一方面,我没有看到任何干净的方法来绕过它。
作为一个切线问题的延续,这也引起了我的另一个巨大担忧:如果我的解释是正确的(甚至有些正确),那么这是否意味着我们需要 Factories 来处理每个对象?!?
这听起来像过度工程!什么是截止?什么时候使用工厂,什么时候不使用?!感谢您对冗长的问题的任何帮助和道歉。简直让我头晕目眩。
【问题讨论】:
-
注意:不能声明抽象静态方法或覆盖静态方法。
标签: java unit-testing dependency-injection junit factory-pattern