2015-10-08 40 views
7

Kod tabanı, yaklaşık 1,5 m'lik bir kod satırıyla, tipik yay tabanlı kurumsal kod tabanıdır. Oldukça az kaynak içerikli dosyalarımız var. Test, bir sorun.Çekirdeği çalışma zamanında değiştirin

Test senaryoları için, bir dizi test-yayın dosyası hazırladım (çoğunlukla ilgili proje yayı bağlamlarını ithal ediyor) ve birkaç fasulye dış servisler için alaylı fasulye içeriyor. Tüm Test sınıfları aynı içerik konfigürasyon dosyalarını kullanır ve işler zamanın% 90'ı kadardır. Ancak bazı durumlarda, alay etmek istediğim bir fasulye olurdu. Ancak, spring-text.xml dosyasını (tüm sınıfları rahatsız edeceği gibi) düzenlemek istemiyorum, ayrıca her bir test sınıfı için ayrı bir xml seti olmasını isterim. Bunu yapmanın çok basit bir deyişi:

@Autowired 
@Qualifier("fundManager") 
FundManager fundManager; 

@Test 
public void testSomething(){ 
    TransactionManager tx = mock(TransactionManager.class); 
    fundManager.setTransactionManager(tx); 
    //now all is well. 
} 

Bu, bazı durumlarda çalışır. Ancak bazen, tüm yeni geçici fasulye tx'un, her zaman kod tabanı boyunca TransactionManager fasulyenin kullanıldığı yerlerde ayarlanması istenir.

Proxy sınıfı IMHO mükemmel bir çözüm değildir, çünkü tüm çekirdekleri bir sarıcıyla sarmak zorunda kalırdım.

@Test 
public void testSomething(){ 
    TransactionManager tx = mock(TransactionManager.class); 
    replace("transactionManagerBean",tx); 
    //For bean with id:transactionManagerBean should be replace with `tx` 
} 

BeanPostProcessor alternatif öneri gibi görünüyor ama onunla birkaç hıçkırık karşılaştı: Bu benim ideal arıyorum budur. Aşağıdaki kod parçası bağlamında genelinde tüm Fasulye yerini alacak Sonra

<?xml version="1.0" encoding="UTF-8"?> 
<beans ...> 
    <context:annotation-config/> 
    <bean id="a" class="test.Test$A"/> 
    <bean id="b" class="test.Test$B"/> 
</beans> 

: Başvurunuzu başlatmak için

public static class A { 
} 

public static class B { 
    @Autowired 
    private A a; 

    @Override 
    public String toString() { 
     return "B [a=" + a + ']'; 
    } 
} 

Ve bahar bağlam:

+0

Neden sadece ihtiyaç duyduğunuz fasulyeleri geçersiz kılan/değiştiren bir test yapılandırması oluşturmuyorsunuz? Bu temelde herhangi bir hack olmadan kutunun dışında çalışır. Sınama durumunuzda, yapılandırmayı yüklemek için XML add '@ ImportResource 'kullandığınızı varsayarak,' @ Configuration 'ifadesini kullanarak bir' public static class 'oluşturun. Şimdi @Bean kamu TransactionManager transactionManager() {return mock (TransactionManager.class);} 'geçersiz kılmak istediğiniz fasulye için 'Bean' yöntemlerini tanımlayın. –

+0

@ M.Deinum Thanks. Evet, bu işe yarar ama aynı zamanda her bir Test sınıfı dosya için farklı sınıf yapılandırma sınıfları oluşturacağım anlamına gelirdi. – Jatin

+0

Neden bu kirletici çekirdeklerin yerini almaya çalışıyor olsa da, bu daha da kötü… –

cevap

4

Eğer fasulye A fasulye B enjekte var düşünün

public static void main(String[] args) throws Exception { 
    ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); 

    System.out.println(ctx.getBean("b")); 

    final A replacement = new A(); 
    for (String name : ctx.getBeanDefinitionNames()) { 
     final Object bean = ctx.getBean(name); 
     ReflectionUtils.doWithFields(bean.getClass(), 
      field -> { 
       field.setAccessible(true); 
       field.set(bean, replacement); 
      }, 
      // Here you can provide your filtering. 
      field -> field.getType().equals(A.class) 
     ); 
    } 

    System.out.println(ctx.getBean("b")); 
} 

Bu örnek, Java 8 + Spring 4.1 ile yapılmıştır. Ancak hem Java hem de Spring'in eski sürümlerinin kodunu değiştirmek basit olurdu.

İlgili konular