2015-10-08 6 views
7

कोडबेस सामान्य वसंत आधारित एंटरप्राइज़ कोडबेस है जो लगभग 1.5 मीटर लाइन कोड के साथ है। हमारे पास वसंत संदर्भ फाइलें हैं। परीक्षण इन्फ्रा एक समस्या है।रनटाइम पर बीन बदलें

परीक्षण के मामलों के लिए, मैंने परीक्षण-वसंत फ़ाइलों का एक और सेट बनाया (ज्यादातर यह प्रासंगिक परियोजना वसंत संदर्भ आयात करता है) और कुछ बीन्स के लिए बाहरी सेवाओं के लिए नकली बीन्स होते हैं। सभी टेस्ट क्लास संदर्भ कॉन्फ़िगरेशन फ़ाइलों के समान सेट का उपयोग करते हैं और चीजें 90% बार अच्छी तरह से होती हैं।

लेकिन कुछ मामलों में, एक बीन होगा जो मैं नकली करना चाहता हूं। लेकिन मैं spring-text.xml को संपादित नहीं करना चाहता (क्योंकि यह सभी वर्गों को परेशान करेगा), और न ही मैं प्रत्येक टेस्ट क्लास के लिए एक्सएमएल का अलग सेट रखना चाहता हूं। ऐसा करने का एक बहुत ही सरल कहना होगा:

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

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

यह कुछ मामलों में काम करता है। लेकिन कभी-कभी, यह वांछित है कि यह नया अस्थायी बीन tx सेट किया जाना चाहिए जहां TransactionManager बीन कोड कोड के दौरान उपयोग किया जा रहा था।

प्रॉक्सी क्लास आईएमएचओ एक अच्छा समाधान नहीं है, क्योंकि मुझे तब सभी सेम एक रैपर के साथ लपेटना होगा।

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

BeanPostProcessor एक वैकल्पिक सुझाव की तरह दिखता है, लेकिन मैं इसके साथ कुछ हिचकी सामना करना पड़ा है: यह है कि मैं क्या आदर्श रहा हूँ है।

+0

आप केवल टेस्ट कॉन्फ़िगरेशन क्यों नहीं बना रहे हैं जो आपको आवश्यक बीन्स को ओवरराइड/प्रतिस्थापित करता है? यह मूल रूप से बिना किसी हैकिंग के आउट-ऑफ-द-बॉक्स काम करता है। आपके परीक्षण मामले में '@ कॉन्फ़िगरेशन' के साथ 'सार्वजनिक स्थैतिक वर्ग' एनोटेट बनाएं, मान लें कि आप कॉन्फ़िगरेशन लोड करने के लिए XML जोड़ें '@ ImportResource' का उपयोग करते हैं। अब उन बीन्स के लिए '@ बीन' विधियों को परिभाषित करें जिन्हें आप ओवरराइड करना चाहते हैं '@ बीन पब्लिक ट्रांजैक्शन मैनेजर लेनदेन प्रबंधक() {रिटर्न मॉक (ट्रांसएक्शन मैनेजर.क्लास);} '। –

+0

@ एम। डीनियम धन्यवाद। हां, यह काम करता है लेकिन इसका मतलब यह भी होगा कि मेरे पास प्रत्येक टेस्ट-क्लास फ़ाइल के लिए कॉन्फ़िगरेशन क्लास का अलग सेट होगा जिससे कक्षा प्रदूषण पैदा हो। – Jatin

+0

बीन्स को बदलने की कोशिश कर रहे प्रदूषण क्यों और भी बदतर होगा ... –

उत्तर

4

आप सेम एक सेम बी में इंजेक्ट किया है कल्पना कीजिए:

public static class A { 
} 

public static class B { 
    @Autowired 
    private A a; 

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

और वसंत संदर्भ आपके आवेदन प्रारंभ करने में:

<?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> 

तो निम्नलिखित स्निपेट संदर्भ भर में सभी सेम एक का स्थान ले लेगा:

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

यह उदाहरण जावा 8 + स्प्रिंग 4.1 के साथ बनाया गया था। हालांकि जावा और स्प्रिंग दोनों के बड़े संस्करणों के लिए कोड को संशोधित करना आसान होगा।

संबंधित मुद्दे