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 的所有剩余方法调用真实方法。