Java Mockito:将真实对象注入私有 @Autowired 字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20270391/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mockito: Inject real objects into private @Autowired fields
提问by user2286693
I'm using Mockito's @Mock
and @InjectMocks
annotations to inject dependencies into private fields which are annotated with Spring's @Autowired
:
我正在使用 Mockito@Mock
和@InjectMocks
注释将依赖项注入到用 Spring 注释的私有字段中@Autowired
:
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Mock
private SomeService service;
@InjectMocks
private Demo demo;
/* ... */
}
and
和
public class Demo {
@Autowired
private SomeService service;
/* ... */
}
Now I would like to also inject realobjects into private @Autowired
fields (without setters). Is this possible or is the mechanism limited to injecting Mocks only?
现在我还想将真实对象注入私有@Autowired
字段(没有 setter)。这是可能的还是仅限于注入 Mocks 的机制?
采纳答案by Dev Blanked
Use @Spy
annotation
使用@Spy
注解
@RunWith(MockitoJUnitRunner.class)
public class DemoTest {
@Spy
private SomeService service = new RealServiceImpl();
@InjectMocks
private Demo demo;
/* ... */
}
Mockito will consider all fields having @Mock
or @Spy
annotation as potential candidates to be injected into the instance annotated with @InjectMocks
annotation. In the above case 'RealServiceImpl'
instance will get injected into the 'demo'
Mockito 会将所有具有@Mock
或@Spy
注释的字段视为要注入到用@InjectMocks
注释注释的实例中的潜在候选者。在上述情况下,'RealServiceImpl'
实例将被注入到“演示”中
For more details refer
有关更多详细信息,请参阅
回答by Yoaz Menda
In Addition to @Dev Blanked answer, if you want to use an existing bean that was created by Spring the code can be modified to:
除了@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);
}
/* ... */
}
This way you don't need to change your code (add another constructor) just to make the tests work.
这样你就不需要为了让测试工作而改变你的代码(添加另一个构造函数)。
回答by davidxxx
Mockito is not a DI framework and even DI frameworks encourage constructor injections over field injections.
So you just declare a constructor to set dependencies of the class under test :
Mockito 不是 DI 框架,甚至 DI 框架也鼓励构造函数注入而不是字段注入。
因此,您只需声明一个构造函数来设置被测类的依赖项:
@Mock
private SomeService serviceMock;
private Demo demo;
/* ... */
@BeforeEach
public void beforeEach(){
demo = new Demo(serviceMock);
}
Using Mockito spy
for the general case is a terrible advise. It makes the test class brittle, not straight and error prone : What is really mocked ? What is really tested ?@InjectMocks
and @Spy
also hurts the overall design since it encourages bloated classes and mixed responsibilities in the classes.
Please read the spy()
javadocbefore using that blindly (emphasis is not mine) :
spy
在一般情况下使用 Mockito是一个糟糕的建议。它使测试类变得脆弱,不直接且容易出错:真正嘲笑的是什么?什么是真正的测试?@InjectMocks
并且@Spy
还会损害整体设计,因为它鼓励类中的臃肿类和混合职责。
请在盲目使用之前阅读spy()
javadoc(重点不是我的):
Creates a spy of the real object. The spy calls realmethods unless they are stubbed. Real spies should be used carefully and occasionally, for example when dealing with legacy code.
As usual you are going to read the
partial mock warning
: Object oriented programming tackles complexity by dividing the complexity into separate, specific, SRPy objects. How does partial mock fit into this paradigm? Well, it just doesn't... Partial mock usually means that the complexity has been moved to a different method on the same object. In most cases, this is not the way you want to design your application.However, there are rare cases when partial mocks come handy: dealing with code you cannot change easily (3rd party interfaces, interim refactoring of legacy code etc.) However, I wouldn't use partial mocks for new, test-driven & well-designed code.
创建真实对象的间谍。间谍调用真正的方法,除非它们被存根。真正的间谍应该谨慎使用,偶尔使用,例如在处理遗留代码时。
像往常一样,您将阅读
partial mock warning
:面向对象的编程通过将复杂性划分为单独的、特定的 SRPy 对象来解决复杂性。部分模拟如何适应这种范式?嗯,它只是没有......部分模拟通常意味着复杂性已转移到同一对象上的不同方法。在大多数情况下,这不是您想要设计应用程序的方式。但是,在极少数情况下,部分模拟会派上用场:处理您无法轻松更改的代码(第 3 方接口、遗留代码的临时重构等)但是,我不会将部分模拟用于新的、测试驱动的 & 以及-设计的代码。
回答by Jonathan S. Fisher
I know this is an old question, but we were faced with the same problem when trying to inject Strings. So we invented a JUnit5/Mockito extension that does exactly what you want: https://github.com/exabrial/mockito-object-injection
我知道这是一个老问题,但我们在尝试注入字符串时遇到了同样的问题。所以我们发明了一个 JUnit5/Mockito 扩展,它完全符合你的要求:https: //github.com/exabrial/mockito-object-injection
EDIT:
编辑:
@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();
}
回答by takacsot
In Spring there is a dedicated utility called ReflectionTestUtils
for this purpose. Take the specific instance and inject into the the field.
在 Spring 中有一个专门ReflectionTestUtils
用于此目的的实用程序。取具体实例并注入该领域。
@Spy
..
@Mock
..
@InjectMock
Foo foo;
@BeforeEach
void _before(){
ReflectionTestUtils.setField(foo,"bar", new BarImpl());// `bar` is private field
}