2013-06-27 32 views
105

Tôi đang cố viết một bài kiểm tra đơn vị cho một bean đơn giản được sử dụng trong chương trình của tôi để xác thực biểu mẫu. Đậu được chú thích bằng @Component và có biến lớp được khởi tạo bằng cách sử dụng @Value("${this.property.value}") private String thisProperty;Populating Spring @Value trong Bài kiểm tra đơn vị

Tôi muốn viết các kiểm tra đơn vị cho các phương thức xác thực trong lớp này, nếu có thể tôi muốn làm như vậy mà không sử dụng tệp thuộc tính . Lý do của tôi đằng sau điều này, là nếu giá trị tôi đang kéo từ các thay đổi tập tin thuộc tính, tôi muốn điều đó không ảnh hưởng đến trường hợp thử nghiệm của tôi. Trường hợp thử nghiệm của tôi đang thử nghiệm mã xác nhận giá trị, chứ không phải giá trị của chính nó.

Có cách nào để sử dụng mã Java bên trong lớp thử nghiệm của tôi để khởi tạo một lớp Java và điền thuộc tính Spring @Value bên trong lớp đó sau đó sử dụng để kiểm tra?

Tôi đã tìm thấy điều này How To dường như gần nhưng vẫn sử dụng tệp thuộc tính. Tôi thà tất cả là mã Java.

Cảm ơn

Trả lời

88

Nếu có thể tôi sẽ thử viết những thử nghiệm đó mà không có bối cảnh mùa xuân. Nếu bạn tạo lớp này trong bài kiểm tra của bạn mà không có mùa xuân, thì bạn có toàn quyền kiểm soát các trường của nó.

Để đặt trường @value bạn có thể sử dụng Springs ReflectionTestUtils - nó có phương thức setField để đặt trường riêng tư.

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

+1

Chính xác những gì tôi đã cố gắng làm và những gì tôi đang tìm kiếm để thiết lập các giá trị bên trong lớp học của tôi, cảm ơn! – Kyle

+1

Hoặc thậm chí không cần phụ thuộc vào mùa xuân bằng cách thay đổi trường thành truy cập mặc định (gói được bảo vệ) để làm cho nó dễ dàng truy cập vào thử nghiệm. –

+2

Ví dụ: 'org.springframework.test.util.ReflectionTestUtils.setField (classUnderTest," field "," value ");' – Olivier

36

Nếu bạn muốn, bạn vẫn có thể chạy thử nghiệm của bạn trong vòng Spring Context và thiết lập các thuộc tính cần thiết bên trong lớp cấu hình Spring. Nếu bạn sử dụng JUnit, sử dụng SpringJUnit4ClassRunner và xác định lớp cấu hình dành riêng cho các bài kiểm tra của bạn như thế:

Các lớp dưới kiểm tra:

@Component 
public SomeClass { 

    @Autowired 
    private SomeDependency someDependency; 

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

Lớp kiểm tra:

@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() { ... } 
} 

Và các lớp cấu hình cho kiểm tra này:

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

Có nói rằng, tôi sẽ không khuyên bạn nên cách tiếp cận này, tôi chỉ cần thêm nó vào đây để tham khảo. Theo tôi, cách tốt hơn là sử dụng nhân vật Mockito. Trong trường hợp đó, bạn không chạy thử nghiệm bên trong Spring, điều này rõ ràng hơn và đơn giản hơn nhiều.

+2

Tôi đồng ý rằng hầu hết logic nên được kiểm tra với Mockito. Tôi muốn có một cách tốt hơn để kiểm tra sự hiện diện và tính chính xác của các chú thích hơn là chạy thử nghiệm thông qua Spring. – Altair7852

15

Điều này dường như làm việc, mặc dù vẫn còn một chút verbose (Tôi muốn một cái gì đó ngắn hơn vẫn):

@BeforeClass 
public static void beforeClass() { 
    System.setProperty("some.property", "<value>"); 
} 

// Optionally: 
@AfterClass 
public static void afterClass() { 
    System.clearProperty("some.property"); 
} 
+0

Tôi nghĩ câu trả lời này là sạch hơn vì nó là Spring bất khả tri, nó hoạt động tốt cho các kịch bản khác nhau, như khi bạn phải sử dụng trình chạy thử nghiệm tùy chỉnh và không thể thêm chú thích '@ TestProperty'. – raspacorp

4

Thêm PropertyPlaceholderConfigurer trong cấu hình đang làm việc cho tôi.

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

}

Và trong lớp thử nghiệm

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

}

57

Kể từ mùa xuân 4.1 bạn có thể thiết lập giá trị thuộc tính chỉ bằng mã bằng cách sử dụng chú thích org.springframework.test.context.TestPropertySource trên cấp độ Bài kiểm tra đơn vị. Bạn có thể sử dụng phương pháp này ngay cả đối với tiêm tính vào trường hợp đậu phụ thuộc

Ví dụ

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

    } 

} 

Lưu ý: Đó là cần thiết để có thể hiện của org.springframework.context.support.PropertySourcesPlaceholderConfigurer trong bối cảnh mùa xuân

Sửa 24-08- 2017: Nếu bạn đang sử dụng SpringBoot 1.4.0 trở lên, bạn có thể khởi tạo các thử nghiệm với chú thích @SpringBootTest@SpringBootConfiguration. Thông tin thêm here

Trong trường hợp của chúng tôi đã SpringBoot mã sau

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

} 
+0

Cảm ơn bạn, cuối cùng ai đó đã trả lời cách ghi đè Giá trị chứ không phải cách đặt trường. Tôi lấy được các giá trị từ trường chuỗi trong PostConstruct và vì vậy tôi cần giá trị chuỗi được thiết lập bởi Spring, không phải sau khi xây dựng. – tequilacat

+0

Tôi rất vui được giúp đỡ –