java - Populating SpringValue أثناء اختبار الوحدة




junit spring-annotations (5)

إذا كنت ترغب في ذلك ، فلا يزال بإمكانك تشغيل الاختبارات في سياق 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);
    }
}

بعد أن قلت ، لا أوصي بهذا النهج ، لقد أضفته هنا للرجوع إليه. في رأيي أفضل طريقة هي استخدام عداء Mockito. في هذه الحالة ، لا تجري اختبارات داخل Spring على الإطلاق ، وهو أمر أكثر وضوحًا وبساطة.

أحاول كتابة اختبار وحدة لحبة بسيطة تستخدم في برنامجي للتحقق من صحة النماذج. يتم وضع @Component الفاصوليا مع @Component ولديها متغير فئة تتم تهيئته باستخدام @Value("${this.property.value}") private String thisProperty;

أود أن أكتب اختبارات الوحدة لطرق التحقق من الصحة داخل هذا الصف ، ولكن إذا كان ذلك ممكنا ، أود أن أفعل ذلك دون استخدام ملف الخصائص. السبب وراء هذا ، هو أنه إذا تغيرت القيمة التي أقوم بها من ملف الخصائص ، أود أن لا يؤثر ذلك على حالة الاختبار الخاصة بي. تقوم حالة الاختبار الخاصة بي باختبار الرمز الذي يقوم بالتحقق من صحة القيمة وليس القيمة نفسها.

هل هناك طريقة لاستخدام شفرة Java داخل فئة الاختبار الخاصة بي لتهيئة فئة Java وملء خاصية SpringValue داخل هذا الصف ثم استخدم ذلك للاختبار؟

لقد وجدت هذا كيف يبدو أن وثيقة ، ولكن لا يزال يستخدم ملف خصائص. أفضل أن يكون كل رمز جافا.

شكر


يبدو أن هذا يعمل ، على الرغم من أنه لا يزال مطولًا بعض الشيء (أحتاج إلى شيء أقصر حتى الآن):

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

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

منذ ربيع 4.1 ، يمكنك إعداد قيم الخصائص في التعليمات البرمجية فقط باستخدام التعليق التوضيحي لـ org.springframework.test.context.TestPropertySource على مستوى فئة اختبارات الوحدات. يمكنك استخدام هذا الأسلوب حتى لحقن الخصائص في حالات الفول المعتمدة

فمثلا

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

  }

}

ملاحظة: من الضروري الحصول على مثال org.springframework.context.support.PropertySourcesPlaceholderConfigurer في سياق الربيع

تحرير 24-08-2017: إذا كنت تستخدم @SpringBootTest @SpringBootConfiguration 1.4.0 وما بعده ، فيمكنك تهيئة الاختبارات باستخدام @SpringBootConfiguration والتعليقات التوضيحية لـ @SpringBootConfiguration . مزيد من المعلومات here

في حالة SpringBoot لدينا التعليمات البرمجية التالية

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

}

إضافة 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());
}

}


@Component و @Bean مختلفين تمامًا ، ولا ينبغي الخلط بينهما.

@Component@Service و @Repository ) للكشف التلقائي عن الفاصوليا وتكوينها تلقائيًا باستخدام المسح على مسار classpath. هناك تخطيط فردي ضمني بين الفئة المشروحة والحبة (أي حبة واحدة لكل فئة). السيطرة على الأسلاك محدودة للغاية مع هذا النهج ، لأنها مجرد تصريحات.

يستخدم @Bean للإعلان صراحة عن حبة واحدة ، بدلاً من السماح لـ Spring بإجراء ذلك تلقائيًا كما هو موضح أعلاه. إنه يزيل إعلان الحبة من تعريف الفئة ، ويسمح لك بإنشاء وتكوين الفاصوليا بالضبط كيف تختار.

للإجابة على سؤالك...

هل كان من الممكن إعادة استخدام التعليق التوضيحي لـ @Component بدلاً من تقديم تعليق توضيحي لـ @Bean ؟

بالتأكيد ، على الأرجح لكنهم اختاروا عدم ذلك ، لأن الاثنين مختلفان تمامًا. الربيع مربك بالفعل بما فيه الكفاية دون تعكير المزيد من المياه.





java spring junit spring-annotations