我使用的是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),我不想仅仅为了测试的目的而创建任何方法。

鉴于此,我如何模拟一个值的一个字段?


当前回答

这是我第三次在谷歌上搜索这篇SO帖子,因为我总是忘记如何模拟@Value字段。虽然接受的答案是正确的,我总是需要一些时间来获得“setField”调用正确,所以至少对我自己,我粘贴了一个示例代码片段在这里:

生产类:

@Value("#{myProps[‘some.default.url']}")
private String defaultUrl;

测试类:

import org.springframework.test.util.ReflectionTestUtils;

ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}", 
//       but simply the FIELDs name ("defaultUrl")

其他回答

这是我第三次在谷歌上搜索这篇SO帖子,因为我总是忘记如何模拟@Value字段。虽然接受的答案是正确的,我总是需要一些时间来获得“setField”调用正确,所以至少对我自己,我粘贴了一个示例代码片段在这里:

生产类:

@Value("#{myProps[‘some.default.url']}")
private String defaultUrl;

测试类:

import org.springframework.test.util.ReflectionTestUtils;

ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}", 
//       but simply the FIELDs name ("defaultUrl")

我想建议一个相关的解决方案,即将带@ value注释的字段作为参数传递给构造函数,而不是使用ReflectionTestUtils类。

而不是这样:

public class Foo {

    @Value("${foo}")
    private String foo;
}

and

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;
    }
}

and

public class FooTest {

    private Foo foo;

    @Before
    public void setUp() {
        foo = new Foo("foo");
    }

    @Test
    public void testFoo() {
        // stuff
    }
}

这种方法的好处:1)我们可以实例化Foo类而不需要依赖容器(它只是一个构造函数),2)我们没有将我们的测试与我们的实现细节耦合(反射使用字符串将我们绑定到字段名,如果我们更改字段名,这可能会导致问题)。

您还可以在测试类中模拟您的属性配置

@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);
   }
}

您可以使用Spring的ReflectionTestUtils的魔力。setField,以避免对代码做任何修改。

michaovich randommal的评论提供了一个例子:

使用ReflectionTestUtils。setField(bean, "fieldName", "value");在测试期间调用bean方法之前。

查看本教程以获取更多信息,尽管您可能不需要它,因为该方法非常易于使用

更新

自Spring 4.2引入以来。RC1现在可以设置一个静态字段,而不必提供类的实例。请参阅文档的这一部分和这个提交。

您可以使用这个神奇的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;
   ...