[英]Mockito: Inject real objects into private @Autowired fields
我正在使用 Mockito 的@Mock
和@InjectMocks
注释将依赖项注入到使用 Spring 的@Autowired
注释的私有字段中:
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Mock
private SomeService service;
@InjectMocks
private Demo demo;
/* ... */
}
和
public class Demo {
@Autowired
private SomeService service;
/* ... */
}
现在我还想将真实对象注入私有@Autowired
字段(没有 setter)。 这是可能的还是仅限于注入 Mocks 的机制?
使用@Spy
注释
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Spy
private SomeService service = new RealServiceImpl();
@InjectMocks
private Demo demo;
/* ... */
}
Mockito 会将所有具有@Mock
或@Spy
注释的字段视为潜在的候选者,以注入到使用@InjectMocks
注释的实例中。 在上述情况下, 'RealServiceImpl'
实例将被注入到“演示”中
有关更多详细信息,请参阅
除了@Dev Blanked 答案之外,如果您想使用由 Spring 创建的现有 bean,则可以将代码修改为:
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Inject
private ApplicationContext ctx;
@Spy
private SomeService service;
@InjectMocks
private Demo demo;
@Before
public void setUp(){
service = ctx.getBean(SomeService.class);
}
/* ... */
}
这样你就不需要为了让测试工作而改变你的代码(添加另一个构造函数)。
Mockito 不是 DI 框架,甚至 DI 框架也鼓励构造函数注入而不是字段注入。
因此,您只需声明一个构造函数来设置被测类的依赖项:
@Mock
private SomeService serviceMock;
private Demo demo;
/* ... */
@BeforeEach
public void beforeEach(){
demo = new Demo(serviceMock);
}
在一般情况下使用 Mockito spy
是一个糟糕的建议。 它使测试类变得脆弱,不直接且容易出错:真正嘲笑的是什么? 什么是真正的测试?
@InjectMocks
和@Spy
也损害了整体设计,因为它鼓励类中的臃肿类和混合职责。
请在盲目使用之前阅读spy()
javadoc (重点不是我的):
创建真实对象的间谍。 间谍调用真正的方法,除非它们被存根。 真正的间谍应该谨慎使用,偶尔使用,例如在处理遗留代码时。
像往常一样,您将阅读
partial mock warning
:面向对象的编程通过将复杂性划分为单独的、特定的 SRPy 对象来解决复杂性。 部分模拟如何适应这种范式? 嗯,它只是没有......部分模拟通常意味着复杂性已转移到同一对象上的不同方法。 在大多数情况下,这不是您想要设计应用程序的方式。但是,在极少数情况下,部分模拟会派上用场:处理您无法轻松更改的代码(第 3 方接口、遗留代码的临时重构等)但是,我不会将部分模拟用于新的、测试驱动的 & 以及-设计的代码。
在 Spring 中有一个专门的实用程序,称为ReflectionTestUtils
用于此目的。 取具体实例并注入该领域。
@Spy
..
@Mock
..
@InjectMock
Foo foo;
@BeforeEach
void _before(){
ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field
}
我知道这是一个老问题,但我们在尝试注入字符串时遇到了同样的问题。 所以我们发明了一个 JUnit5/Mockito 扩展,它完全符合你的要求: https : //github.com/exabrial/mockito-object-injection
编辑:
@InjectionMap
private Map<String, Object> injectionMap = new HashMap<>();
@BeforeEach
public void beforeEach() throws Exception {
injectionMap.put("securityEnabled", Boolean.TRUE);
}
@AfterEach
public void afterEach() throws Exception {
injectionMap.clear();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.