복붙노트

[SPRING] Mockito로 Spring에서 autowired @Value 필드를 어떻게 조롱합니까?

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

이걸 감안할 때, 어떻게 한 필드에 값을 조롱 할 수 있습니까?

해결법

  1. ==============================

    1.코드의 수정을 피하기 위해 Spring의 ReflectionTestUtils.setField의 마술을 사용할 수 있습니다.

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

    메소드가 매우 사용하기 쉽기 때문에이 튜토리얼에서 더 많은 정보를 얻을 수있다.

    최신 정보

    Spring 4.2.RC1이 소개 된 이래 클래스의 인스턴스를 제공 할 필요없이 정적 필드를 설정할 수있게되었습니다. 문서의이 부분과이 커밋을 참조하십시오.

  2. ==============================

    2.@Value 필드를 조롱하는 방법을 항상 잊어 버렸기 때문에 이제는이 세 번째 게시물로 나 자신을 봤습니다. 받아 들여진 대답이 맞지만, "setField"콜을받을 시간이 필요합니다. 적어도 혼자서 여기에 예제 스 니펫을 붙여 넣으십시오.

    @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")
    
  3. ==============================

    3.테스트 구성에 속성 구성을 조롱 할 수도 있습니다.

    테스트 구성에 속성 구성을 조롱 할 수도 있습니다.

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

    4.ReflectionTestUtils 클래스를 사용하는 대신 @ Value-annotated 필드를 생성자에 매개 변수로 전달하는 관련 솔루션을 제안하고 싶습니다.

    ReflectionTestUtils 클래스를 사용하는 대신 @ Value-annotated 필드를 생성자에 매개 변수로 전달하는 관련 솔루션을 제안하고 싶습니다.

    대신 이것 :

    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) 구현 세부 사항에 테스트를 연결하지 않아도됩니다 (리플렉션은 문자열을 사용하여 필드 이름에 연결 함, 필드 이름을 변경하면 문제가 발생할 수 있음).

  5. ==============================

    5.이 매직 스프링 테스트 주석을 사용할 수 있습니다 :

    이 매직 스프링 테스트 주석을 사용할 수 있습니다 :

    @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;
       ...
    
  6. ==============================

    6.이 문제를 해결하는 한 가지 방법은 테스트 및 스프링 주입에 사용되는 생성자 삽입을 사용하도록 클래스를 변경하는 것입니다. 더 이상 반사 :)

    이 문제를 해결하는 한 가지 방법은 테스트 및 스프링 주입에 사용되는 생성자 삽입을 사용하도록 클래스를 변경하는 것입니다. 더 이상 반사 :)

    따라서 생성자를 사용하여 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");
    
  7. from https://stackoverflow.com/questions/23162777/how-do-i-mock-an-autowired-value-field-in-spring-with-mockito by cc-by-sa and MIT license