我有一个Spring MVC @Controller
的构造函数:
@Autowired
public AbcController(XyzService xyzService, @Value("${my.property}") String myProperty) {/*...*/}
我想为这个Controller编写一个独立的单元测试:
@RunWith(MockitoJUnitRunner.class)
public class AbcControllerTest {
@Mock
private XyzService mockXyzService;
private String myProperty = "my property value";
@InjectMocks
private AbcController controllerUnderTest;
/* tests */
}
有什么方法可以让@InjectMocks
注入我的String属性吗?我知道我不能模拟一个String,因为它是不可变的,但是我可以在这里注入一个普通的String吗?
在这种情况下,@InjectMocks
默认注入一个null。如果我把它放在myProperty
上,@Mock
可以理解地抛出一个异常。是否还有另一个注解我错过了,它只是意味着“注入这个确切的对象,而不是它的一个Mock”?
8条答案
按热度按时间xdnvmnnf1#
Mockito不能做到这一点,但Apache Commons实际上有一种方法可以使用其内置的实用程序来做到这一点。您可以将其放入JUnit中的一个函数中,该函数在Mockito注入其余的mocks之后运行,但在测试用例运行之前运行,如下所示:
xmakbtuz2#
由于您使用的是Spring,因此可以使用
spring-test
模块中的org.springframework.test.util.ReflectionTestUtils
。它巧妙地 Package 了在对象上设置字段或在类上设置静态字段(沿着其他实用程序方法)。af7jpaap3#
你不能在Mockito上这样做,因为正如你自己提到的,
String
就是final
,不能被模仿。有一个
@Spy
注解可以在 * 真实的 * 对象上工作,但它有与@Mock
相同的限制,因此您无法监视String
。没有注解告诉Mockito只注入该值而不做任何模拟或监视。这将是一个很好的功能。也许建议在Mockito Github repository上使用它。
如果你不想改变你的代码,你必须手动示例化你的控制器。
只有重构控制器才能得到一个基于注解的测试,它可以使用一个只包含一个属性的自定义对象,或者是一个包含多个属性的配置类。
这可以被注入到控制器中。
你可以模仿并注入这个。
这并不是很直接,但至少你可以有一个纯粹的基于注解的测试,只需要一点存根。
hkmswyz64#
在这种情况下不要使用@InjectMocks。
做到:
juzqafwq5#
解决方法简单:你应该为对象类型注入构造函数,而对于原始/最终依赖项,你可以简单地使用setter注入,这对这个场景来说很好。
所以这个:
将改为:
测试中的
@Mock
注入将简单如下:这就足够了。去
Reflections
是不可取的!请尽可能避免在生产代码中使用反射!!
对于
Jan Groot
的解决方案,我必须提醒你,它将变得非常讨厌,因为你将不得不删除所有的@Mock
,甚至@InjectMocks
,并将不得不初始化,然后手动注入它们,这对于2个依赖项听起来很容易,但对于7个依赖项,代码将成为一场噩梦(见下文)。mm9b1k5b6#
你可以使用的是:org.mockito.internal.util.reflection.Whitebox
1.重构“AbcController”类构造函数
1.在Test类的“before”方法中,使用Whitebox.setInternalState方法指定所需的任何字符串
k7fdbhmy7#
如果您不想更改代码,那么使用ReflectionTestUtils.setField方法How do I mock an autowired @Value field in Spring with Mockito?
isr3a4wc8#
TL;DR
解释:你会惊讶地发现它是多么简单,但却很棘手。尝试用途:@Autowired和**@InjectMock**注解在一起。
通过这种方式,你的实际对象将首先被加载,然后需要被监视或模仿的对象将被注入。你的实际对象将具有已经通过属性填充的值。