7

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方法。

4

4 回答 4

3

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

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

于 2013-11-06T22:53:35.933 回答
1

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.

于 2013-11-06T23:24:55.450 回答
1

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

此问题代码的问题:

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

以下是您在 questionCode 解决上述问题时可能应该使用的内容:

文章.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 单元测试。

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

    }

}
于 2013-11-10T17:31:02.207 回答
1

您可以利用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();
        ...
    }

}

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

于 2016-07-07T12:26:29.917 回答