गाइडिंग में ओवरराइडिंग बाइंडिंग


138

मैंने अभी-अभी Guice के साथ खेलना शुरू किया है, और एक उपयोग-मामला जिसके बारे में मैं सोच सकता हूं, वह यह है कि एक परीक्षण में मैं सिर्फ एक बंधन को ओवरराइड करना चाहता हूं। मुझे लगता है कि मैं उत्पादन स्तर के बाकी हिस्सों का उपयोग करना चाहता हूं ताकि यह सुनिश्चित हो सके कि सब कुछ सही ढंग से सेट हो और दोहराव से बचा जा सके।

तो कल्पना कीजिए कि मेरे पास निम्नलिखित मॉड्यूल हैं

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}

और मेरे परीक्षण में मैं केवल इंटरफ़ेस को ओवरराइड करना चाहता हूं, जबकि इंटरफ़ेसए और इंटरफ़ेसबी को चातुर्य में रखते हुए, इसलिए मैं कुछ ऐसा चाहूंगा:

Module testModule = new Module() {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(new ProductionModule(), testModule);

मैंने निम्नलिखित को भी आज़माया है, बिना किसी भाग्य के:

Module testModule = new ProductionModule() {
    public void configure(Binder binder) {
        super.configure(binder);
        binder.bind(InterfaceC.class).to(MockC.class);
    }
};
Guice.createInjector(testModule);

किसी को पता है कि क्या यह संभव है कि मैं क्या चाहता हूँ या मैं पूरी तरह से गलत पेड़ भौंक रहा हूँ ??

--- का पालन करें: ऐसा लगता है कि अगर मैं इंटरफ़ेस पर @ImforceedBy टैग का उपयोग करता हूं, तो मैं वह प्राप्त कर सकता हूं जो मैं चाहता हूं और फिर परीक्षण के मामले में एक बाध्यकारी प्रदान करें, जो बीच में 1-1 मानचित्रण होने पर अच्छी तरह से काम करता है इंटरफ़ेस और कार्यान्वयन।

इसके अलावा, एक सहकर्मी के साथ इस पर चर्चा करने के बाद, ऐसा लगता है कि हम एक पूरे मॉड्यूल को ओवरराइड करने की सड़क पर उतरेंगे और सुनिश्चित करेंगे कि हमारे पास हमारे मॉड्यूल सही ढंग से परिभाषित हैं। ऐसा लगता है कि यह एक समस्या का कारण बन सकता है, जहां एक मॉड्यूल में एक बंधन को गलत तरीके से स्थानांतरित किया जाता है और इसे स्थानांतरित करने की आवश्यकता होती है, इस प्रकार संभवतः परीक्षणों का भार टूट जाता है क्योंकि बाइंडिंग अब ओवरराइड होने के लिए उपलब्ध नहीं हो सकता है।


7
जैसे "गलत पेड़ को भौंकना" वाक्यांश: डी
बोरिस पावलोविक्व

जवाबों:


149

यह वह उत्तर नहीं हो सकता है जिसकी आप तलाश कर रहे हैं, लेकिन यदि आप इकाई परीक्षण लिख रहे हैं, तो आपको संभवतः इंजेक्टर का उपयोग नहीं करना चाहिए और न ही हाथ से नकली या नकली वस्तुओं को इंजेक्ट करना चाहिए।

दूसरी ओर, यदि आप वास्तव में एक एकल बंधन को बदलना चाहते हैं, तो आप उपयोग कर सकते हैं Modules.override(..):

public class ProductionModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(ConcreteA.class);
        binder.bind(InterfaceB.class).to(ConcreteB.class);
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
}
public class TestModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}
Guice.createInjector(Modules.override(new ProductionModule()).with(new TestModule()));

विवरण देखें यहाँ

लेकिन Modules.overrides(..)अनुशंसा के लिए javadoc के रूप में , आपको अपने मॉड्यूल को इस तरह से डिज़ाइन करना चाहिए कि आपको बाइंडिंग को ओवरराइड करने की आवश्यकता न हो। आपके द्वारा दिए गए उदाहरण में, आप InterfaceCएक अलग मॉड्यूल के बंधन को आगे बढ़ाकर पूरा कर सकते हैं ।


9
धन्यवाद अल्बर्ट, जो मुझे किसी भी रास्ते पर ले जाता है जो मुझे चाहिए। यह एक रिलीज में अभी तक थो है! और यह एकीकरण परीक्षणों के लिए है, इकाई परीक्षणों के लिए नहीं, जो कि मैं यह सुनिश्चित करना चाहता हूं कि बाकी सब कुछ सही तरीके से बनाया जा रहा है
tddmonkey

1
मैंने कोड में एक ठोस उदाहरण जोड़ा है। क्या यह आपको और आगे ले जाता है?
अल्बर्ट

1
जब तक मैं गलत नहीं हूँ, ऐसा करते समय ovverideउचित खो देता है Stage(यानी विकास व्यवस्थित रूप से उपयोग किया जाता है)।
पेडेस्चेन

4
आकर महत्त्व रखता है। जब आपकी निर्भरता ग्राफ बढ़ता है, तो हाथ से वायरिंग काफी दर्द हो सकता है। जब वायरिंग परिवर्तन आपको मैन्युअल रूप से अपने सभी वायरिंग स्थानों को अपडेट करने की आवश्यकता होती है। ओवरराइडिंग आपको स्वचालित रूप से संभालने की अनुमति देता है।
योसिबा

3
@ पेप्सचेन गुइसा 3 में एक बग है जो मैंने गुएस 4 के लिए तय किया है
टावियन बार्न्स

9

वंशानुक्रम का उपयोग क्यों नहीं किया जाता है? आप overrideMeविधि में अपने विशिष्ट बाइंडिंग को ओवरराइड कर सकते हैं , साझा कार्यान्वयन को configureविधि में छोड़ सकते हैं ।

public class DevModule implements Module {
    public void configure(Binder binder) {
        binder.bind(InterfaceA.class).to(TestDevImplA.class);
        overrideMe(binder);
    }

    protected void overrideMe(Binder binder){
        binder.bind(InterfaceC.class).to(ConcreteC.class);
    }
};

public class TestModule extends DevModule {
    @Override
    public void overrideMe(Binder binder) {
        binder.bind(InterfaceC.class).to(MockC.class);
    }
}

और अंत में अपना इंजेक्टर इस तरह बनाएं:

Guice.createInjector(new TestModule());

3
@Overrideकाम करने के लिए प्रतीत नहीं होता। खासकर अगर यह एक विधि पर किया जाता है कि @Providesकुछ।
सासंका पंगुलुरी

4

यदि आप अपने उत्पादन मॉड्यूल को बदलना नहीं चाहते हैं और यदि आपके पास एक डिफ़ॉल्ट मावेन-जैसी परियोजना संरचना है

src/test/java/...
src/main/java/...

आप ConcreteCअपनी मूल निर्देशिका के लिए उसी पैकेज का उपयोग करके अपनी परीक्षण निर्देशिका में एक नया वर्ग बना सकते हैं । इसके बाद आपके परीक्षण निर्देशिका से बाइंड InterfaceCकिया जाएगा ConcreteCजबकि अन्य सभी इंटरफेस आपके उत्पादन वर्गों के लिए बाध्य होंगे।


2

आप जुकिटो का उपयोग करना चाहते हैं जहां आप प्रत्येक परीक्षण वर्ग के लिए अपने कस्टम कॉन्फ़िगरेशन की घोषणा कर सकते हैं।

@RunWith(JukitoRunner.class)
class LogicTest {
    public static class Module extends JukitoModule {

        @Override
        protected void configureTest() {
            bind(InterfaceC.class).to(MockC.class);
        }
    }

    @Inject
    private InterfaceC logic;

    @Test
    public testLogicUsingMock() {
        logic.foo();
    }
}

1

एक अलग सेटअप में, हमारे पास अलग-अलग मॉड्यूल में परिभाषित एक से अधिक गतिविधियाँ हैं। जिस गतिविधि को इंजेक्ट किया जा रहा है, वह एंड्रॉइड लाइब्रेरी मॉड्यूल में है, जिसमें Android Robififest.xml फ़ाइल में स्वयं का रोबोग्यूइस मॉड्यूल परिभाषा है।

सेटअप इस तरह दिखता है। लाइब्रेरी मॉड्यूल में ये परिभाषाएँ हैं:

AndroidManifest.xml:

<application android:allowBackup="true">
    <activity android:name="com.example.SomeActivity/>
    <meta-data
        android:name="roboguice.modules"
        android:value="com.example.MainModule" />
</application>

फिर हमारे पास एक प्रकार का इंजेक्शन है:

interface Foo { }

Foo के कुछ डिफ़ॉल्ट कार्यान्वयन:

class FooThing implements Foo { }

MainMule Foo के लिए FooThing कार्यान्वयन को कॉन्फ़िगर करता है:

public class MainModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Foo.class).to(FooThing.class);
    }
}

और अंत में, एक गतिविधि जो फू का सेवन करती है:

public class SomeActivity extends RoboActivity {
    @Inject
    private Foo foo;
}

उपभोग करने वाले एंड्रॉइड एप्लिकेशन मॉड्यूल में, हम इसका उपयोग करना चाहते हैं SomeActivity, लेकिन परीक्षण प्रयोजनों के लिए, अपने स्वयं के इंजेक्शन लगाएं Foo

public class SomeOtherActivity extends Activity {
    @Override
    protected void onResume() {
        super.onResume();

        Intent intent = new Intent(this, SomeActivity.class);
        startActivity(intent);
    }
}

क्लाइंट अनुप्रयोग के लिए मॉड्यूल से निपटने का खुलासा करने के लिए एक तर्क दे सकता है, हालांकि, हमें ज्यादातर घटकों को इंजेक्ट करने की आवश्यकता है क्योंकि लाइब्रेरी मॉड्यूल एक एसडीके है, और टुकड़ों को उजागर करने के बड़े निहितार्थ हैं।

(याद रखें, यह परीक्षण के लिए है, इसलिए हम SomeActivity के इंटर्नल को जानते हैं, और जानते हैं कि यह एक (पैकेज दृश्यमान) जू का उपभोग करता है)।

जिस तरह से मैंने पाया कि काम करना समझ में आता है; परीक्षण के लिए सुझाए गए ओवरराइड का उपयोग करें :

public class SomeOtherActivity extends Activity {
    private class OverrideModule
            extends AbstractModule {

        @Override
        protected void configure() {
            bind(Foo.class).to(OtherFooThing.class);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RoboGuice.overrideApplicationInjector(
                getApplication(),
                RoboGuice.newDefaultRoboModule(getApplication()),
                Modules
                        .override(new MainModule())
                        .with(new OverrideModule()));
    }

    @Override
    protected void onResume() {
        super.onResume();

        Intent intent = new Intent(this, SomeActivity.class);
        startActivity(intent);
    }
}

अब, जब SomeActivityशुरू किया जाता है, तो यह OtherFooThingइसके इंजेक्शन के Fooलिए मिलेगा ।

यह एक बहुत ही विशिष्ट स्थिति है, जहां, हमारे मामले में, अन्य स्थितियों का उपयोग करने के लिए, अन्य स्थितियों का उपयोग करते हुए, अन्य स्थितियों के लिए फूफ़्टिंग का उपयोग किया गया था, जबकि अन्य स्थितियों में रिकॉर्ड करने के लिए आंतरिक रूप से OtherFooThing का उपयोग किया गया था।

ध्यान रखें, हम अपने यूनिट परीक्षणों में उपयोग कर रहे हैं#newDefaultRoboModule , और यह त्रुटिपूर्ण रूप से काम करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.