java – 依赖注入如何促进可测试性

前端之家收集整理的这篇文章主要介绍了java – 依赖注入如何促进可测试性前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直在阅读 Factory模式,并且发现了一些文章,建议将Factory模式与依赖注入结合使用,以最大限度地提高可重用性和可测试性.虽然我还没有找到这个Factory-DI混合的任何具体例子,但我将尝试给出一些我的解释的代码示例.但是,我的问题是关于这种方法如何提高可测试性.

我的解释:

所以我们有一个Widget类:

  1. public class Widget {
  2. // blah
  3. }

我们想要包含一个WidgetFactory来控制Widgets的构造:

  1. public interface WidgetFactory {
  2.  
  3. public abstract static Widget getWidget();
  4. }
  5.  
  6. public class StandardWidgetFactory implements WidgetFactory {
  7.  
  8. @Override
  9. public final static Widget getWidget() {
  10. // Creates normal Widgets
  11. }
  12. }
  13.  
  14. public class TestWidgetFactory implements WidgetFactory {
  15.  
  16. @Override
  17. public final static Widget getWidget() {
  18. // Creates test/mock Widgets for unit testing purposes
  19. }
  20. }

虽然这个例子使用的是Spring DI(这是我唯一经验过的API),但是如果我们谈论的是Guice或任何其他的IoC框架并不重要;这里的想法是,我们现在要在运行时注入正确的WidgetFactory实现,具体取决于我们是在测试代码还是正常运行.在Spring中,bean配置可能如下所示:

  1. <bean id="widget-factory" class="org.me.myproject.StandardWidgetFactory"/>
  2. <bean id="test-widget-factory" class="org.me.myproject.TestWidgetFactory"/>
  3.  
  4. <bean id="injected-factory" ref="${valueWillBeStdOrTestDependingOnEnvProp}"/>

然后,在代码中:

  1. WidgetFactory wf = applicationContext.getBean("injected-factory");
  2. Widget w = wf.getWidget();

这样,环境(部署级别)变量(可能在.properties文件中定义)决定Spring DI是否会注入StandardWidgetFactory或TestWidgetFactory.

我做得对吗?!?这似乎是一个非常多的基础设施只是为我的Widget获得良好的可测试性.并不是说我反对它,但这对我来说只是过度工程化.

我的挂断:

我问这个的原因是因为我将在其他包中有其他对象,其中包含在其中使用Widget对象的方法.也许是这样的:

  1. public class Fizz {
  2. public void doSomething() {
  3.  
  4. WidgetFactory wf = applicationContext.getBean("injected-factory");
  5. Widget widget = wf.getWidget();
  6.  
  7. int foo = widget.calculatePremable(this.rippleFactor);
  8.  
  9. doSomethingElse(foo);
  10. }
  11. }

如果没有这个看似过度设计的庞大设置,我就无法将“模拟小部件”注入到Fizz :: doSomething()的单元测试中.

所以我被撕裂了:一方面,我觉得我正在过度思考 – 我可能正在做的事情(如果我的解释不正确).另一方面,我没有看到任何干净的方式绕过它.

作为一个切向问题,这也引起了我的另一个巨大关注:如果我的解释是正确的(甚至有些正确),那么这是否意味着我们需要每个对象的工厂?!?

这听起来像过度工程!什么是截止?什么是沙子中的线条划分何时使用工厂,什么时候不用?!感谢您对冗长问题的任何帮助和道歉.这让我头晕目眩.

解决方法

DI / IoC有助于测试,因为您可以轻松地决定使用哪种实现,而无需修改使用它的代码.这意味着您可以注入已知的实现来执行特定功能,例如,模拟Web服务故障,保证对函数的良好(或不良)输入等.

工厂不需要使DI / IoC工作.是否需要工厂完全取决于使用细节.

  1. public class Fizz {
  2.  
  3. @Inject // Guice,new JEE,etc. or
  4. @Autowired // Spring,or
  5. private Widget widget;
  6.  
  7. public void doSomething() {
  8. int foo = widget.calculatePremable(this.rippleFactor);
  9. doSomethingElse(foo);
  10. }
  11.  
  12. }

猜你在找的Java相关文章