我正在使用Spring 3.1.4.RELEASE和Mockito 1.9.5。在我的春课课上,我有:
@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
),我不想仅仅为了测试而创建任何方法。
鉴于此,如何模拟该字段的值?
答案 0 :(得分:103)
您可以使用Spring ReflectionTestUtils.setField
的魔力,以避免对您的代码进行任何修改。
查看this教程以获取更多信息,尽管您可能不需要它,因为该方法非常易于使用
<强>更新强>
自Spring 4.2.RC1引入以来,现在可以设置静态字段而无需提供类的实例。请参阅文档的this部分和this提交。
答案 1 :(得分:65)
这是我第三次使用Google搜索这篇文章,因为我总是忘记如何模拟@Value字段。虽然接受的答案是正确的,但我总是需要一些时间让“setField”调用正确,所以至少对我自己来说,我在这里粘贴了一个示例片段:
生产类:
@Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
测试类:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(myClassUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.CLASS, use the class itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
答案 2 :(得分:30)
您还可以将属性配置模拟到测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
@Configuration
public static class MockConfig{
@Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
@Value("#{myProps['default.url']}")
private String defaultUrl;
@Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
答案 3 :(得分:13)
我想建议一个相关的解决方案,即将@Value
- 带注释的字段作为参数传递给构造函数,而不是使用ReflectionTestUtils
类。
而不是:
public class Foo {
@Value("${foo}")
private String foo;
}
和
public class FooTest {
@InjectMocks
private Foo foo;
@Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
@Test
public void testFoo() {
// stuff
}
}
这样做:
public class Foo {
private String foo;
public Foo(@Value("${foo}") String foo) {
this.foo = foo;
}
}
和
public class FooTest {
private Foo foo;
@Before
public void setUp() {
foo = new Foo("foo");
}
@Test
public void testFoo() {
// stuff
}
}
这种方法的好处:1)我们可以在没有依赖容器的情况下实例化Foo类(它只是一个构造函数),2)我们没有将我们的测试与我们的实现细节相结合(反射关系)我们使用字符串的字段名称,如果我们更改字段名称可能会导致问题。)
答案 4 :(得分:12)
您可以使用这个神奇的Spring Test注释:
@TestPropertySource(properties = { "my.spring.property=20" })
请参阅 org.springframework.test.context.TestPropertySource
例如,这是测试类:
@ContextConfiguration(classes = { MyTestClass.Config.class })
@TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
@Bean
MyClass getMyClass() {
return new MyClass ();
}
}
@Resource
private MyClass myClass ;
@Test
public void myTest() {
...
这是具有属性的类:
@Component
public class MyClass {
@Value("${my.spring.property}")
private int mySpringProperty;
...
答案 5 :(得分:0)
还请注意,我的课程中没有明确的“ setter”方法(例如setDefaultUrl),并且我不想为测试目的而创建任何方法。
解决此问题的一种方法是将您的类更改为使用构造函数注入,该类用于测试和Spring注入。没有更多的反思:)
因此,您可以使用构造函数传递任何String:
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
@Value("#{myProps['default.url']}") String defaultUrl,
@Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
在测试中,只需使用它即可:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
答案 6 :(得分:0)
我使用了下面的代码,它对我有用:
@InjectMocks
private AccessFeatureActivationStrategy activationStrategy = new AccessFeatureActivationStrategy();
@Before
public void setUp() {
ReflectionTestUtils.setField(activationStrategy, "constantFromConfigFile", 3);
}
参考:https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
答案 7 :(得分:0)
只要有可能,我都会将字段可见性设置为受包保护,以便可以从测试类中访问它。我使用Guava的@VisibleForTesting批注对此进行了说明(以防下一个人想知道为什么它不是私有的)。这样,我不必依赖字段的字符串名称,一切都保持类型安全。
我知道这与我们在学校教过的标准封装实践背道而驰。但是,一旦团队中达成这样的协议,我便发现它是最实用的解决方案。