2013-11-01 38 views
6

mockito确实不能模拟CGLIB已经增强的对象吗?模拟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();它实际上调用了真正的函数。仔细看看articleMock得到了两次增强。 autowiring的一个原因和spying的第二次原因。

如果我不能窥探enhaced对象,那么我如何在我的集成测试中测试getArticle()方法,以便我可以验证是否返回了正确的DTO。

注:我其实不想测试文件系统调用的方法。只是数据库的。那就是为什么我需要测试getArticle方法。

+0

以下是我发现的[文档](http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#doNothing())我不模仿地看到问题。你是否尝试过自己创建'Article',而不是自动装配(或者至少在自动装配后验证了正确性)? – atomman

+0

是的,如果我自己创造“文章”,我可以窥探。但我必须自动装载它,因为在我的应用程序中,每个对象都是通过自动装配创建的,如果我自己启动“Article”,则Article类中的字段为空(例如,reqHandler对象)。如果我也启动这些字段,那么这些类中的字段为空,链接继续。 – samach

+0

过滤的代码和您的问题不适合 - getArticle()有问题,getArticleContents()在代码中 - 它造成了一些混淆。你应该考虑提供更多的'IntegrationTest'代码。 – Cebence

回答

3

如果我理解正确,你的班级由Spring连线。只有在没有接口的情况下,Spring才会使用CGLIB来确保事务行为,这是由对象实现的。如果有一个接口,它使用简单的JDK动态代理。 (请参阅http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html

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

1

如果您作为真正的单元测试运行,而不是作为集成测试运行,则不需要在具有Spring自动装载的容器中运行。在你的一个评论中,我想你提到了这个,你注意到有一连串的链接对象引用,你也必须提供。但是有一种解决方法。 Mockito提供了一些预定义的Answer类,您可以使用它们初始化您的模拟。你可能想看看RETURNS_DEEP_STUBS,这可能会让你解决这个问题。

1

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

这个问题的代码问题:

  • 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的一个不好名称,因为它是通用的。我会建议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); 

    } 

} 
0

您可以利用AdditionalAnswers.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的所有其他方法调用真实方法 - 注释bean。