【问题标题】:Spring Best practice for Dependency InjectionSpring 依赖注入的最佳实践
【发布时间】:2016-07-01 02:35:21
【问题描述】:

我对春季的 DI 有点困惑

public interface A{
    void methodA();
}
public class AImpl implements A{
    public void methodA(){
          // todo something
    }
}

public interface B{
    void methodB();
}
public class BImpl implements B{
     public void methodB(){
       //todo somethong
     }
}

我有两个接口 A 和 B 和 2 个类实现它。 所以,我有 2 个实现接口 C 的类,它依赖于接口 A 和 B

这是案例 1:

public interface C{
    void methodC();
}

public class CAutowired implements C{
    @Autowired
    private A a;
    @Autowired
    private B b;

    public void methodC(){
       a.methodA();
       b.methodB();
    }
}

文件 .xml 配置

  <beans>
       <bean id="classA" class="com.example.AImpl" />
       <bean id="classB" class="com.example.BImpl" />
       <bean id="classC" class="com.example.CAutowired" />
    <beans>

在这种情况下,我有一个问题: - 当我为 CAutowired 类编写 unitTest 时如何模拟 A 和 B

这是案例 2:

public class CInitInject implements C{
    private A a;
    private B b;

    public CInitInject(A a, B b){
       this.a = a;
       this.b = b;
    }

    public void methodC(){
       a.methodA();
       b.methodB();
    }
}

文件 .xml 配置

  <beans>
       <bean id="classA" class="com.example.AImpl" />
       <bean id="classB" class="com.example.BImpl" />
       <bean id="classC" class="com.example.CInitInject">
             <constructor-arg ref="classA" />
             <constructor-arg ref="classB" />
       </bean>
    <beans>

在这种情况下,我在 .NET 中获得了相同的 DI 方法。我可以通过注入来模拟 A 和 B 进入构造函数。示例:

@Mock
private A aMock;
@Mock
private B bMock;

private C c;

public void setUp(){
   c = new CInitInject(aMock, bMock);
}

@Test
public void test(){
   // todo Test somemethod
}

最后,我有一个问题

  1. 案例 1 和案例 2 之间的最佳做法是什么?
  2. 如何在单元测试时模拟它

【问题讨论】:

    标签: spring unit-testing dependency-injection mocking mockito


    【解决方案1】:

    (1)

    今天的习惯是将 bean 注入到构造函数中。

    这被认为是最佳实践,因为它严格告知该类的用户(在本例中为CInitInject 的用户),该类需要什么才能正常工作。用户不必像 setter 那样猜测需要哪些依赖项。

    (1.1)

    “案例 1”的代码示例捆绑了两种代码样式,您可能希望避免这种情况。

    在注释驱动编码和XML之间选择是很常见的。

    在这种情况下,如果您选择使用注释,您的代码将如下所示(注意不涉及 XML):

    public interface C{
        void methodC();
    }
    
    @Bean(name="a")
    public class AImpl implements A{
        public void methodA(){
            // todo something
        }
    }
    
    @Bean
    public class CAutowired implements C{
        @Autowired
        private A a;
        @Autowired
        private B b;
    
        public void methodC(){
           a.methodA();
           b.methodB();
        }
    }
    

    请参阅example,了解如何使用帮助代码来完成这项工作。

    (1.2)

    如果你选择使用注解驱动的编码,下面是一个将bean注入构造函数的例子:

    @Bean
    public class CAutowired implements C {
        private A a;
        private B b;
    
        @Autowired
        public CAutowired(A a, B b) {
            this.a = a;
            this.b = b;
        }
    }
    

    (1.3)

    在使用注解时,避免在系统中大量使用 Spring 也是很常见的。因此,有些人创建的类既知道 spring 类,也知道其他类(例如 CAutowired,现在将重命名为 CImpl),并且只有他们使用 @Autowired@Bean 注释。 示例:

    //just an example, you'll think of how this works for YOU
    public class OneOfSomeSpringManagers {
        public OneOfSomeSpringManagers() {
            C c = getC(getA());
        }
    
        @Bean
        public A getA() {
            ...
        }
    
        ...
    }
    

    (2)

    在单元测试中使用Mockito to mock the injected dependencies

    【讨论】:

    • 我认为你使用 Bean 注解的方式和我使用 XML 到 Configuration 的方式基本相似。使用 Bean 注解通知应用程序上下文,无需在 XML 文件中声明。但在这个问题中,我想知道 Inject 构造函数或 Autowired 注释之间的最佳实践是什么,以及如何测试它
    • 我在 (1)(2) 下回答了你。您不必使用我在 (1.1)-(1.3) 中的建议。
    • 感谢您的帮助。我找到了问题的解决方案
    猜你喜欢
    • 2010-12-11
    • 1970-01-01
    • 2019-05-23
    • 2011-12-30
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    相关资源
    最近更新 更多