我使用的是Spring 3.1.4.RELEASE和Mockito 1.9.5。在我的Spring类中,我有:
@Value("#{myProps['default.url']}")
private String defaultUrl;
@Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
在我的JUnit测试中,我目前已经这样设置了:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
我想模拟我的“defaultUrl”字段的值。注意我不想模拟其他字段的值-我想保持它们的原样,只有“defaultUrl”字段。还请注意我的类中没有显式的“setter”方法(例如setDefaultUrl
),我不想仅仅为了测试的目的而创建任何方法。
既然如此,我如何模拟该字段的值呢?
9条答案
按热度按时间lx0bsm1f1#
您可以使用Spring的
ReflectionTestUtils.setField
的魔力来避免对代码进行任何修改。Michał Stochmal中的注解提供了一个示例:
在测试期间调用
bean
方法之前使用ReflectionTestUtils.setField(bean, "fieldName", "value");
。查看this教程以获得更多信息,不过您可能不需要它,因为该方法非常容易使用
自从Spring 4.2.RC1引入以来,现在可以设置一个静态字段,而不必提供类的示例。参见文档的这一部分和this commit。
gmol16392#
这是我第三次在谷歌上搜索这个帖子,因为我总是忘记如何模拟一个@Value字段。虽然接受的答案是正确的,但我总是需要一些时间来正确调用“setField”,所以至少我自己在这里粘贴了一个示例片段:
生产等级:
测试类别:
xmq68pz93#
你可以使用这个神奇的Spring Test注解:
参见org.springframework.test.context.TestPropertySource
例如,下面是测试类:
这个类的属性是:
nue99wik4#
我想建议一个相关的解决方案,那就是将带
@Value
注解的字段作为参数传递给构造函数,而不是使用ReflectionTestUtils
类。而不是这个:
以及
请执行以下操作:
以及
这种方法的好处:1)我们可以示例化Foo类而不需要依赖容器(它只是一个构造函数),以及2)我们没有将测试与实现细节耦合(反射使用字符串将我们与字段名绑定,如果我们更改字段名,这可能会导致问题)。
sqxo8psd5#
您还可以将属性配置模拟到测试类中
62lalag46#
我使用了下面的代码,它为我工作:
参考:https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
fcy6dtqo7#
还要注意,我的类中没有显式的“setter”方法(例如setDefaultUrl),我也不想仅仅为了测试而创建任何方法。
解决这个问题的一个方法是将类更改为使用构造函数注入,它可用于测试和Spring注入。
因此,您可以使用构造函数传递任何String:
在你的测试中,就使用它:
ax6ht2ek8#
只要有可能,我就将字段的可见性设置为包保护的,这样就可以从测试类访问它。我使用Guava的@VisibleForTesting注解对此进行了记录(以防下一个人想知道为什么它不是私有的)。这样我就不必依赖字段的字符串名称,一切都保持类型安全。
我知道这违背了我们在学校里学到的标准封装实践,但是一旦团队中达成了某种共识,我就发现这是最实用的解决方案。
5t7ly7z59#
另一种方法是使用
@SpringBootTest
注解properties
字段。这里我们重写
example.firstProperty
属性:正如你所看到的,它只覆盖了一个属性,
@SpringBootTest
中没有提到的属性保持不变,因此,当我们只需要覆盖测试的特定属性时,这是一个很好的解决方案。对于单个属性,可以不使用大括号:
答复来自:https://www.baeldung.com/spring-tests-override-properties#springBootTest
我还鼓励您尽可能将属性作为构造函数中的参数传递,就像在Dherik answer(https://stackoverflow.com/a/52955459/1673775)中那样,因为它使您能够在单元测试中轻松地模拟属性。
然而,在集成测试中,您通常不会手动创建对象,而是:
@Autowired
则具有
@SpringBootTest
的该解决方案可能是有用的。