模拟 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();时,它实际上调用了真正的函数。仔细看文章Mock 被增强了两次。autowiring的一个原因和spying的第二个原因。

如果我无法监视增强的对象,那么如何在集成测试中测试 getArticle() 方法,以便验证是否返回了正确的 DTO。

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

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

也许你可以尝试提取一个接口,让Spring使用动态代理。也许那时莫基托可以表现得更好。

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

请您用现成的可编译代码更新您的问题。下面是一些代码审查建议:

此问题代码的问题:

  • 文章.java缺少导入:org.springframework.beans.factory.annotation.Autowired
  • 文章.java缺少导入:org.springframework.transaction.annotation.Transactional
  • 文章.java属性语法问题:dbRequestHandler
  • 文章.java属性语法问题:文件系统请求处理程序
  • 文章.java方法没有初始化的返回语句:文章DTO

以下是您在问题代码时可能应该使用的内容,并修复了上述问题:

文章.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 来说是一个糟糕的名字,因为它是泛型的。我建议使用ArticleTest进行java单元测试。

文章测试.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);
    }
}

您可以使用 ExtraalAnswers.delegatesTo 方法。在下面的示例中,secondProxyDoingMocking 声明创建类似间谍的东西(与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注释 bean 的所有剩余方法调用真实方法。

相关内容

  • 没有找到相关文章

最新更新