Arjun Nair
Arjun Nair

Reputation: 471

Springs @Autowiring functionality Along with Mocking

Issue : I have a class A

class A {

      @Autowired
      EdocumentDAO eDocumentDAO;

      public void createDocument(DocumentType docType)
      {
            String DocID= saveIndocRepo();//To be Mocked
            docType.setID(DocID);

            isSaved = eDocumentDAO.save()//Autowired

      }
      private String saveIndocRepo()
      {
          //Code to save in Repo in another platform and return the DOC_ID
      }


}

My A_Test class

@ContextConfiguration({ "classpath:test-beans.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
class A_test {

        A a = Mockito.spy(new A());

        Mockito.doReturn("DOC_ID").when(a).saveIndocRepo();
        a.createDocument(docType);      
}

Requirement : I have method saveIndocRepo() which interacts with the external service and save the document in their repo. So this needs to be mocked.

which is called in the createDocument() and a the mocked value should be returned.After the DocID is received the other Document Details are saved into the DB (for which I have configured a Derby In-memory DB). The EdocumentDAO works on the Autowiring which is instantiated by the springs.

Issue: When I try to mock the method(saveInDocRepo) its Mocked successfully but the Autowiring fails. Which results in the JUnit failure. When I remove the mocking then the Autowiring is executing perfectly.

Is there anything that I am missing. Or is my approach not correct. Experts - Please advise an appropriate solution.

Upvotes: 1

Views: 297

Answers (3)

Arjun Nair
Arjun Nair

Reputation: 471

Thanks all, for you help.

Solution:

@ContextConfiguration({ "classpath:test-beans.xml" })
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")

@Spy
@InjectMocks
A a = new A();

@Autowired
@Spy
EdocumentDAO eDocumentDAO;
class A_test {

        Mockito.doReturn("DOC_ID").when(a).saveIndocRepo();
        a.createDocument(docType);      
}

Now when the createDocument() method is called, the saveInDocRepo() is mocked to return "DOC_ID" and the eDocumentDAO.save() works perfectly. Its @Spy which is used for partial mocking, saved the day.

Upvotes: 1

bric3
bric3

Reputation: 42223

You can use the shorthand injection of mockito and not rely on Spring on this one :

class ATest {
    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
    @Mock EdocumentDAO dao;
    @InjectMocks A a;

    @Test
    public void the_test() {
        doReturn("DOC_ID").when(dao).saveIndocRepo();
        a.createDocument(docType);
    }
}

Note this is pseudo code, as I cannot use an IDE right now

Upvotes: 0

Guillaume F.
Guillaume F.

Reputation: 6463

You have to Mock an Interface and not the Class itself. Create an Interface with the public methods of the Class to Mock.

In your example above, you are Spying on A, but A depends on EdocumentDAO. You have to Mock this Class too.

@Mock
EdocumentDAO edocumentDAOMock;

or, my favorite way with Spring since you can implement a mock behavior:

@Bean
private EdocumentDAO getEdocumentDAOMock() {
    return mock(EdocumentDAO.class);
}

Also, since you are using Spring, you can't use new A(), you have to use Spring to instantiate a Bean, otherwise the autowired annotation won't work.

Upvotes: 0

Related Questions