복붙노트

[SPRING] 단위 테스트 중 Spring @Value 채우기

SPRING

단위 테스트 중 Spring @Value 채우기

양식을 검증하기 위해 내 프로그램에서 사용되는 간단한 bean에 대한 Unit Test를 작성하려고합니다. bean은 @Component로 주석 처리되고 @Value ( "$ {this.property.value}")를 사용하여 초기화되는 클래스 변수를가집니다. private String thisProperty;

이 클래스 내부의 유효성 검사 메서드에 대한 단위 테스트를 작성하고 싶지만 가능한 경우 속성 파일을 사용하지 않고 수행하고 싶습니다. 이것에 대한 나의 추론은 속성 파일에서 가져온 값이 바뀌면 테스트 케이스에 영향을 미치지 않기를 바란다. 내 테스트 케이스는 값 자체가 아닌 값의 유효성을 검사하는 코드를 테스트하는 것이다.

테스트 클래스 내에서 Java 코드를 사용하여 Java 클래스를 초기화하고 해당 클래스 내에 Spring @Value 속성을 채워 테스트 할 수 있습니까?

나는이 방법이 가까이있는 것처럼 보이지만 여전히 특성 파일을 사용하고 있음을 발견했다. 오히려 모두 Java 코드가됩니다.

감사

해결법

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

    1.가능한 경우 Spring 컨텍스트없이 테스트를 작성하려고합니다. 테스트하지 않고 봄에이 클래스를 만들면 필드를 완전히 제어 할 수 있습니다.

    가능한 경우 Spring 컨텍스트없이 테스트를 작성하려고합니다. 테스트하지 않고 봄에이 클래스를 만들면 필드를 완전히 제어 할 수 있습니다.

    @value 필드를 설정하려면 Springs ReflectionTestUtils를 사용할 수 있습니다.이 필드에는 private 필드를 설정하는 setField 메소드가 있습니다.

    @see JavaDoc : ReflectionTestUtils.setField (java.lang.Object, java.lang.String, java.lang.Object)

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

    2.Spring 4.1부터는 Unit Tests 클래스 레벨에서 org.springframework.test.context.TestPropertySource 주석을 사용하여 코드에서 속성 값을 설정할 수 있습니다. 이 접근법을 사용하여 종속 Bean 인스턴스에 특성을 주입 할 수도 있습니다.

    Spring 4.1부터는 Unit Tests 클래스 레벨에서 org.springframework.test.context.TestPropertySource 주석을 사용하여 코드에서 속성 값을 설정할 수 있습니다. 이 접근법을 사용하여 종속 Bean 인스턴스에 특성을 주입 할 수도 있습니다.

    예를 들어

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = FooTest.Config.class)
    @TestPropertySource(properties = {
        "some.bar.value=testValue",
    })
    public class FooTest {
    
      @Value("${some.bar.value}")
      String bar;
    
      @Test
      public void testValueSetup() {
        assertEquals("testValue", bar);
      }
    
    
      @Configuration
      static class Config {
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer propertiesResolver() {
            return new PropertySourcesPlaceholderConfigurer();
        }
    
      }
    
    }
    

    참고 : Spring 컨텍스트에서 org.springframework.context.support.PropertySourcesPlaceholderConfigurer의 인스턴스를 가져야합니다.

    24-08-2017 편집 : Spring Boot 1.4.0 이상을 사용하는 경우 @SpringBootTest 및 @SpringBootConfiguration 주석을 사용하여 테스트를 초기화 할 수 있습니다. 여기에 대한 자세한 정보

    Spring Boot의 경우 다음과 같은 코드가 있습니다.

    @SpringBootTest
    @SpringBootConfiguration
    @RunWith(SpringJUnit4ClassRunner.class)
    @TestPropertySource(properties = {
        "some.bar.value=testValue",
    })
    public class FooTest {
    
      @Value("${some.bar.value}")
      String bar;
    
      @Test
      public void testValueSetup() {
        assertEquals("testValue", bar);
      }
    
    }
    
  3. ==============================

    3.원할 경우 Spring Context 내에서 테스트를 실행하고 Spring 구성 클래스 내에서 필수 속성을 설정할 수있다. JUnit을 사용하는 경우 SpringJUnit4ClassRunner를 사용하고 다음과 같이 테스트를위한 전용 구성 클래스를 정의하십시오.

    원할 경우 Spring Context 내에서 테스트를 실행하고 Spring 구성 클래스 내에서 필수 속성을 설정할 수있다. JUnit을 사용하는 경우 SpringJUnit4ClassRunner를 사용하고 다음과 같이 테스트를위한 전용 구성 클래스를 정의하십시오.

    테스트중인 클래스 :

    @Component
    public SomeClass {
    
        @Autowired
        private SomeDependency someDependency;
    
        @Value("${someProperty}")
        private String someProperty;
    }
    

    테스트 클래스 :

    @RunWith(SpringJUnit4ClassRunner.class) 
    @ContextConfiguration(classes = SomeClassTestsConfig.class)
    public class SomeClassTests {
    
        @Autowired
        private SomeClass someClass;
    
        @Autowired
        private SomeDependency someDependency;
    
        @Before
        public void setup() {
           Mockito.reset(someDependency);
    
        @Test
        public void someTest() { ... }
    }
    

    이 테스트의 구성 클래스는 다음과 같습니다.

    @Configuration
    public class SomeClassTestsConfig {
    
        @Bean
        public static PropertySourcesPlaceholderConfigurer properties() throws Exception {
            final PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
            Properties properties = new Properties();
    
            properties.setProperty("someProperty", "testValue");
    
            pspc.setProperties(properties);
            return pspc;
        }
        @Bean
        public SomeClass getSomeClass() {
            return new SomeClass();
        }
    
        @Bean
        public SomeDependency getSomeDependency() {
            // Mockito used here for mocking dependency
            return Mockito.mock(SomeDependency.class);
        }
    }
    

    그 말은, 나는이 접근법을 추천하지 않을 것이고, 나는 그것을 참조 용으로 여기에 추가했다. 내 의견으로는 훨씬 좋은 방법은 모치토 주자를 사용하는 것입니다. 이 경우 Spring 내에서 전혀 테스트를 실행하지 않아 훨씬 명확하고 간단합니다.

  4. ==============================

    4.이것은 여전히 ​​약간 장황하지만 (나는 더 짧은 것을 좋아할 것입니다.) 작동합니다.

    이것은 여전히 ​​약간 장황하지만 (나는 더 짧은 것을 좋아할 것입니다.) 작동합니다.

    @BeforeClass
    public static void beforeClass() {
        System.setProperty("some.property", "<value>");
    }
    
    // Optionally:
    @AfterClass
    public static void afterClass() {
        System.clearProperty("some.property");
    }
    
  5. ==============================

    5.구성에 PropertyPlaceholderConfigurer를 추가하는 작업이 저에게 효과적입니다.

    구성에 PropertyPlaceholderConfigurer를 추가하는 작업이 저에게 효과적입니다.

    @Configuration
    @ComponentScan
    @EnableJpaRepositories
    @EnableTransactionManagement
    public class TestConfiguration {
    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        builder.setType(EmbeddedDatabaseType.DERBY);
        return builder.build();
    }
    
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPackagesToScan(new String[] { "com.test.model" });
        // Use hibernate
        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
        entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
        return entityManagerFactoryBean;
    }
    
    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.show_sql", "false");
        properties.put("hibernate.dialect", "org.hibernate.dialect.DerbyDialect");
        properties.put("hibernate.hbm2ddl.auto", "update");
        return properties;
    }
    
    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }
    
    @Bean
    PropertyPlaceholderConfigurer propConfig() {
        PropertyPlaceholderConfigurer placeholderConfigurer = new PropertyPlaceholderConfigurer();
        placeholderConfigurer.setLocation(new ClassPathResource("application_test.properties"));
        return placeholderConfigurer;
    }
    

    }

    그리고 테스트 클래스에서

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringApplicationConfiguration(classes = TestConfiguration.class)
    public class DataServiceTest {
    
    @Autowired
    private DataService dataService;
    
    @Autowired
    private DataRepository dataRepository;
    
    @Value("${Api.url}")
    private String baseUrl;
    
    @Test
    public void testUpdateData() {
        List<Data> datas = (List<Data>) dataRepository.findAll();
        assertTrue(datas.isEmpty());
        dataService.updateDatas();
        datas = (List<Data>) dataRepository.findAll();
        assertFalse(datas.isEmpty());
    }
    

    }

  6. ==============================

    6.유니 터리와 통합에서 테스트 할 수있는 클래스 만들기

    유니 터리와 통합에서 테스트 할 수있는 클래스 만들기

    스프링 컨테이너를 사용하지 않고 일반 단위 테스트를 작성하고 Spring 구성 요소 클래스에 대한 통합 테스트를 작성하려면이 클래스를 Spring의 유무에 관계없이 사용할 수 있어야한다. 유닛 테스트에서 컨테이너를 실행하는 것이 필요하지 않을 때 실행하는 것은 로컬 빌드의 속도를 늦추는 나쁜 습관입니다. 원하지 않습니다. 나는이 대답을 덧붙였다. 왜냐하면 여기서 어떤 대답도이 구별을 나타내는 것처럼 보이지 않으므로 그들은 실행중인 컨테이너에 체계적으로 의존한다.

    그래서 당신이 클래스의 내부로 정의 된이 속성을 이동해야한다고 생각 :

    @Component
    public class Foo{   
        @Value("${property.value}") private String property;
        //...
    }
    

    Spring에 의해 삽입 될 생성자 매개 변수에 넣는다 :

    @Component
    public class Foo{   
        private String property;
    
        public Foo(@Value("${property.value}") String property){
           this.property = property;
        }
    
        //...         
    }
    

    단위 테스트 예제

    Spring을 사용하지 않고 Foo를 인스턴스화하고 생성자에게 속성의 값을 주입 할 수 있습니다.

    public class FooTest{
    
       Foo foo = new Foo("dummyValue");
    
       @Test
       public void doThat(){
          ...
       }
    }
    

    통합 테스트 예제

    @SpringBootTest의 속성 속성 덕분에 스프링 부트로 컨텍스트에서 속성을 주입 할 수 있습니다.

    @SpringBootTest(properties="property.value=dummyValue")
    public class FooTest{
    
       @Autowired
       Foo foo;
    
       @Test
       public void doThat(){
           ...
       }    
    }
    

    @TestPropertySource의 대안으로 사용할 수도 있지만 추가 주석을 추가합니다.

    @SpringBootTest
    @TestPropertySource("property.value=dummyValue")
    public class FooTest{ ...}
    

    (Spring Boot없이) Spring을 사용하면 좀 더 복잡해질 것입니다.하지만 Spring Boot없이 Spring을 오래 사용하지 않았기 때문에 나는 멍청한 것을 말하는 것을 선호하지 않습니다.

  7. from https://stackoverflow.com/questions/17353327/populating-spring-value-during-unit-test by cc-by-sa and MIT license