[spring] Mockito로 Spring에서 autowired @Value 필드를 어떻게 모의합니까?

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”필드 만 그대로 유지하고 싶습니다. 또한 setDefaultUrl클래스에 명시적인 “setter”메소드 (예 :)가 없으며 테스트 목적으로 만 생성하고 싶지 않습니다.

이를 감안할 때 해당 필드의 값을 어떻게 모의 할 수 있습니까?



답변

ReflectionTestUtils.setField코드를 수정하는 것을 피하기 위해 Spring의 마법을 사용할 수 있습니다 .

방법은 사용하기 매우 쉽기 때문에 필요하지 않을 수 있지만 더 자세한 정보는 튜토리얼을 확인하십시오.

최신 정보

Spring 4.2.RC1이 도입 된 이후로 클래스의 인스턴스를 제공하지 않고도 정적 필드를 설정할 수 있습니다. 문서 의이 부분 과이 커밋을 참조하십시오 .


답변

@Value 필드를 조롱하는 방법을 항상 잊어 버렸기 때문에 이제 세 번째 로이 SO 게시물을 검색했습니다. 받아 들여진 대답은 맞지만 “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")


답변

속성 구성을 테스트 클래스로 모의 할 수도 있습니다.

@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를 사용하는 대신 -annotated 필드를 생성자에 매개 변수로 전달하는 관련 솔루션을 제안하고 싶습니다 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) 테스트를 구현 세부 사항에 연결하지 않습니다 (반영은 문자열을 사용하여 필드 이름에 연결하고 필드 이름을 변경하면 문제가 발생할 수 있습니다.)


답변

이 마법의 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;
   ...


답변

나는 아래 코드를 사용했고 그것은 나를 위해 일했습니다.

@InjectMocks
private ClassABC classABC;

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

참조 : https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/


답변

또한 내 클래스에는 명시적인 “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");