1

I have some confusion about DI in spring

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
     }
}

I have two interface A and B and 2 class implements it. So, I have 2 Class that implement interface C, it depend on Interface A and B

This is case 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();
    }
}

File .xml config

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

In this case, i have a question: - How to Mock A and B when i write unitTest for class CAutowired

This is case 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();
    }
}

File .xml config

  <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>

In this case, i get DI method the same in .NET. I can Mock A and B by inject into constructor. Example:

@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
}

End of all, I have a question

  1. What is best practice between case 1 and case 2?
  2. How to Mock it when unit test
Phong Nguyen
  • 173
  • 3
  • 15

1 Answers1

0

(1)

It is customary today to inject beans into the constructor.

It is considered the best practice because it strictly informs users of the class (in this case, users of CInitInject) what is expected for this class in order for it to do its job properly. The users don't have to guess which dependencies are expected as happens with setters.

(1.1)

Your code sample for "case 1" is bundling two code stylings, and you might want to avoid that.

It is common to choose between annotation driven coding and XML.

For that case, should you have chosen to use annotations, your code would have looked like this (notice no XML is involved):

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();
    }
}

See example of how to use the helping code to make this work.

(1.2)

Should you choose to use annotation-driven coding, here's an example of injecting beans into the constructor:

@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)

It is also common to avoid hard-wiring Spring so much into your system, when using annotations. Therefore, some people create classes that are aware of both spring and other classes (such as CAutowired that would now be renamed to CImpl) and only they use @Autowired and @Bean annotations. Example:

//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)

Use Mockito to mock the injected dependencies in unit tests.

Community
  • 1
  • 1
Eeko
  • 106
  • 9
  • I think that your way using Bean annotation and my way using XML to Configuration is basic similar. Using Bean annotation to inform applicationcontext without declare in XML file. But in this problem, I want to know what is best practice between Inject constructor or by Autowired annotation, and how to test it for that ways – Phong Nguyen Jul 01 '16 at 06:32
  • I answered you under **(1)** and **(2)**. You don't have to use my suggestions from (1.1)-(1.3). – Eeko Jul 01 '16 at 09:36
  • Thanks for your help. I found solution for my question – Phong Nguyen Jul 04 '16 at 01:48