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();
它实际上调用了真正的函数。仔细看看articleMock会增强两次。造成autowiring
的{{1}}和第二次原因的一个原因。
如果我无法监视enhaced对象,那么如何在Integration测试中测试spying
方法,以便我可以验证是否返回了正确的DTO。
注意:我实际上不想测试执行文件系统调用的方法。只是DB的。这就是为什么我需要测试getArticle()
方法。
答案 0 :(得分:3)
如果我理解正确,你的课程是由Spring连接的。 Spring仅在没有由对象实现的接口时才使用CGLIB来确保事务行为。如果有接口,它使用简单的JDK动态代理。 (见http://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch08s06.html)
也许您可以尝试提取接口,并让Spring使用动态代理。也许那么Mockito可以表现得更好。
答案 1 :(得分:1)
如果您作为真正的单元测试运行而不是作为集成测试运行,则无需在具有Spring autowire的容器中运行。在你的一条评论中,我认为你提到尝试这个,并且你注意到你必须提供一组无限的链式对象引用。但有一种解决方法。 Mockito提供了一些预定义的Answer
类,您可以使用它们初始化模拟。您可能需要查看RETURNS_DEEP_STUBS,这可能会解决您的问题。
答案 2 :(得分:1)
请您使用随时可用的可编辑代码更新您的问题。以下是一些代码审查建议:
此问题代码的问题:
以下是您在使用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名称,因为它是通用的。我建议用于Java单元测试的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);
}
}
答案 3 :(得分:1)
您可以使用AdditionalAnswers.delegatesTo方法。在下面的示例中,secondProxyDoingMocking
声明创建类似间谍的东西(与spy()
方法的实现相比),除了它使用&#34;轻量级&#34;方法委派。
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。