Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Spring中用Mockito模拟自动连接的@Value字段?_Spring_Mockito_Autowired_Value Initialization - Fatal编程技术网

如何在Spring中用Mockito模拟自动连接的@Value字段?

如何在Spring中用Mockito模拟自动连接的@Value字段?,spring,mockito,autowired,value-initialization,Spring,Mockito,Autowired,Value Initialization,我使用的是Spring3.1.4.RELEASE和Mockito1.9.5。在我的春季课程中,我有: @Value("#{myProps['default.url']}") private String defaultUrl; @Value("#{myProps['default.password']}") private String defaultrPassword; // ... 从我的JUnit测试中,我目前设置如下: @RunWith(SpringJUnit4ClassRunne

我使用的是Spring3.1.4.RELEASE和Mockito1.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
),我不想仅仅为了测试而创建任何方法


鉴于此,如何模拟该字段的值?

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

来自的注释提供了一个示例:

使用ReflectionTestUtils.setField(bean,“fieldName”,“value”)bean
方法之前

查看教程了解更多信息,尽管您可能不需要它,因为该方法非常容易使用

更新


自从Spring4.2.RC1引入以来,现在可以设置静态字段,而不必提供类的实例。请参阅部分文档并提交。

您还可以将属性配置模拟到测试类中

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

这已经是我第三次在谷歌上搜索这篇文章了,因为我总是忘了如何模拟@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;
}

这样做:

public class Foo {

    private String foo;

    public Foo(@Value("${foo}") String foo) {
        this.foo = foo;
    }
}


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

您可以使用此magic Spring测试注释:

@TestPropertySource(properties = { "my.spring.property=20" }) 

例如,这是测试类:

@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;
   ...
还要注意,我的类中没有显式的“setter”方法(例如setDefaultUrl),我不想仅仅为了测试而创建任何方法

解决此问题的一种方法是将类更改为使用构造函数注入,该注入用于测试和Spring注入。不再思考:)

因此,您可以使用构造函数传递任何字符串:

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");

我使用了以下代码,它对我有效:

@InjectMocks
private ClassABC classABC;

@Before
public void setUp() {
    ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}

参考:

只要有可能,我将字段可见性设置为package protected,以便可以从测试类访问它。我用番石榴的注释记录了这一点(以防下一个家伙想知道为什么它不是私人的)。这样我就不必依赖于字段的字符串名,所有内容都保持类型安全


我知道这违反了我们在学校学到的标准封装实践。但是,一旦团队中同意这样做,我发现这是最实用的解决方案。

为了防止链接失效:使用
ReflectionTestUtils.setField(bean,“fieldName”,“value”)bean
方法之前执行code>。这是模拟从属性文件检索的属性的好方法。@MichałStochmal,这样做将产生以下结果:field是私有的java.lang.IllegalStateException:无法访问方法:Class org.springframework.util.ReflectionUtils无法访问org.springframework.util.ReflectionUtils.HandlerReflectionException(ReflectionUtils.java:112)上带有修饰符“”的类com.kaleidofin.app.service.impl.CVLKRAProvider的成员在org.springframework.util.ReflectionUtils.setField(ReflectionUtils.java:655)中,缺点是:如果有人弄乱了注释,例如使用了属性“bar”而不是“foo”,那么测试仍然有效。我只是有这个例子。@NilsEl Himoud对于OP问题来说,这是一个公平的观点,但是您提出的问题对于使用反射utils vs构造函数并没有任何好处或坏处。这个答案的要点是考虑构造函数而不是反射util(公认的答案)。马克,谢谢你的回答,我很感激这个调整的简单和干净。这里一样…+1我也做了同样的调整,但仍然没有反映出这应该是公认的答案。请注意,我自己的参考:您需要模拟您正在使用的所有@value,您不能模拟第一个值,然后从属性中注入第二个值。如果每个测试需要不同的配置,有没有办法使用它?
MySpringClass MySpringClass  = new MySpringClass("anyUrl", "anyPassword");
@InjectMocks
private ClassABC classABC;

@Before
public void setUp() {
    ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}