Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking CGLIB enhanced objects

Is it true that mockito can't mock objects that were already enhanced by CGLIB?

public class Article {

     @Autowired
     private dbRequestHandler

     @Autowired
     private filesystemRequestHandler

     @Transactional
     public ArticleDTO getArticleContents() {

         //extractText() and then save the data in DTO
         //extractImages() and then save the data in DTO
         // some other calls to other databases to save data in dto

       return articleDTO;

     }
     public void extractText() {

        //call to DB

   }

   public void extractImages() {

        // call to file system

   }
}


public class IntegrationTest {

  @Autowired
  private Article article;

  //setup method {

  articleMock = Mockito.spy(article);

  doNothing().when(articleMock).extractImages();
 }
}

In the above example when it comes to doNothing().when(articleMock).extractImages(); it actually calls the real function. On a closer look articleMock gets enhanced two times. One cause of autowiring and second time cause of spying.

If I can't spy on enhaced objects, then how can I test the getArticle() method in my Integration test, so that I can verify a proper DTO is returned.

Note : I actually don't want to test the method which does filesystem calls. just the DB ones. thats why I need to test the getArticle method.

like image 879
samach Avatar asked Nov 01 '13 19:11

samach


2 Answers

If I understand correctly your class is wired by Spring. Spring uses CGLIB to ensure transactional behaviour only if there is no interface, which is implemented by your object. If there is an interface, it uses simple JDK Dynamic Proxies. (see http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html)

Maybe you could try to extract an interface, and let Spring to use dynamic proxies. Maybe then Mockito could perform better.

like image 74
Gábor Lipták Avatar answered Sep 21 '22 04:09

Gábor Lipták


If you run as a true unit test and not as an integration test, you need not run in a container having Spring autowire for you. In one of your comments, I think you alluded to trying this, and you noted that there was an endless set of chained object references which you would have to provide as well. But there is a way around that. Mockito provides some predefined Answer classes that you can initialize your mock with. You may want to look at RETURNS_DEEP_STUBS, which will possibly get you around this problem.

like image 33
Kevin Welker Avatar answered Sep 20 '22 04:09

Kevin Welker