模拟CGLIB增强对象

mockito无法模拟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(); } } 

在上面的例子中,当谈到doNothing().when(articleMock).extractImages(); 它实际上称之为真正的function。 仔细看看articleMock会增强两次。 autowiring和第二次spying原因的一个原因。

如果我不能监视增强的对象,那么如何在我的Integration测试中测试getArticle()方法,以便我可以validation是否返回了正确的DTO。

注意:我实际上不想测试文件系统调用的方法。 只是DB的。 这就是为什么我需要测试getArticle方法。

如果我理解正确,你的课程是由Spring连接的。 Spring仅在没有由对象实现的接口时才使用CGLIB来确保事务行为。 如果有接口,它使用简单的JDK动态代理。 (见http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html )

也许你可以试着提取一个接口,让Spring使用动态代理。 也许那么Mockito可以表现得更好。

如果您作为真正的unit testing运行而不是作为集成测试运行,则无需在具有Spring自动assembly的容器中运行。 在你的一条评论中,我认为你提到尝试这个,你注意到你必须提供一组无限的链式对象引用。 但是有一种解决方法。 Mockito提供了一些预定义的Answer类,您可以使用它们初始化模拟。 您可能需要查看RETURNS_DEEP_STUBS ,这可能会解决您的问题。

请您使用随时可用的可编译代码更新您的问题。 以下是一些代码审查建议:

此问题代码的问题:

  • Article.java缺少导入: org.springframework.beans.factory.annotation.Autowired
  • Article.java缺少import: org.springframework.transaction.annotation.Transactional
  • Article.java属性语法问题: dbRequestHandler
  • Article.java属性语法问题: filesystemRequestHandler
  • Article.java方法没有初始化的return语句: articleDTO

以下是您在使用questionCode时应该使用的内容,修复了上述问题:

Article.java

 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; public class Article { @Autowired private Object dbRequestHandler; @Autowired private Object 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 ArticleDTO articleDTO = null; return articleDTO; } public void extractText() { // call to DB } public void extractImages() { // call to file system } } 

IntegrationTest.java是一个糟糕的testClass名称,因为它是通用的。 我建议用于Javaunit testing的ArticleTest。

ArticleTest.java

 import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.springframework.beans.factory.annotation.Autowired; @RunWith(PowerMockRunner.class) @PrepareForTest(ClassWithPrivate.class) public class ArticleTest { @InjectMocks private Article cut; @Mock private Object dbRequestHandler; @Mock private Object filesystemRequestHandler; @Test public void testeExtractImages() { /* Initialization */ Article articleMock = Mockito.spy(cut); /* Mock Setup */ Mockito.doNothing().when(articleMock).extractImages(); /* Test Method */ ArticleDTO result = cut.getArticleContents(); /* Asserts */ Assert.assertNull(result); } } 

您可以使用AdditionalAnswers.delegatesTo方法。 在下面的示例中, secondProxyDoingMocking声明创建类似spy的东西(与spy()方法的实现比较),除了它使用“轻量级”方法委托。

 import org.mockito.AdditionalAnswers; public class ArticleTest { @Autowired private Article firstProxyDoingAutowiring; @Test public void testExtractImages() { Article secondProxyDoingMocking = Mockito.mock(Article.class, Mockito.withSettings().defaultAnswer( AdditionalAnswers.delegatesTo(firstProxyDoingAutowiring) ) ); Mockito.doNothing().when(secondProxyDoingMocking).extractImages(); ... } } 

我没有测试这个例子,但是我从我的工作代码中汇总了它。 我的用例类似:给定方法返回常量值,为Spring @Transactional -annotated bean的所有剩余方法调用实数方法。