2016-11-03 15 views
5

मैंने एक उदाहरण एप्लिकेशन बनाया है (हां, यह वास्तव में केवल एक उदाहरण है और यह बहुत समझ में नहीं आता है लेकिन एंड्रॉइड क्लीन आर्किटेक्चर और डैगर 2 में निर्भरता इंजेक्शन को समझने के लिए अच्छा है)। मेरे कोड github पर उपलब्ध है। (पुराने। this पोस्ट देखें) उदाहरण ऐप बस चलते आप एक EditText में एक नाम टाइप करें और यदि आप बटन दबाएँ आप एक संदेश "नमस्ते YourName"एंड्रॉइड टेस्टकेस में डैगर 2 निर्भरता इंजेक्शन

मैं तीन अलग-अलग है घटक: ApplicationComponent, ActivityComponent और FragmentComponent

  • ActivityModule
  • FragmentModule
  • InteractorModule

InteractorModule एक MainInteractor प्रदान करता है: FragmentComponent तीन मॉड्यूल शामिल हैं।

@Module 
public class InteractorModule { 

    @Provides 
    @PerFragment 
    MainInteractor provideMainInteractor() { 
     return new MainInteractor(); 
    } 
} 

मेरी गतिविधि-unittest में मैं नकली इस MainInteractor करना चाहते हैं। इस इंटरैक्टर में सिर्फ एक विधि public Person createPerson(String name) है जो एक व्यक्ति वस्तु बना सकती है। FakeMainInteractor में एक ही विधि है लेकिन हमेशा आपके द्वारा पारित पैरामीटर के "नकली व्यक्ति" नाम के साथ एक व्यक्ति वस्तु बनाता है।

public class FakeMainInteractor { 
    public Person createPerson(final String name) { 
     return new Person("Fake Person"); 
    } 
} 

मैं पहले से वर्णित ईवे घटक के लिए पहले से ही टेस्टकंपोनेंट्स बनाता हूं। और TestFragmentComponent में मैंने TestInteractorModule के साथ InteractorModule को बदल दिया।

@PerFragment 
@Component(dependencies = TestApplicationComponent.class, modules = {ActivityModule.class, FragmentModule.class, TestInteractorModule.class}) 
public interface TestFragmentComponent { 
    void inject(MainFragment mainFragment); 

    void inject(MainActivity mainActivity); 
} 

यह उदाहरण एक गैर-परीक्षण संदर्भ में अच्छी तरह से चल रहा है। MainActivity में मेरे पास initializeInjector() नामक एक विधि है जहां मैं FragmentComponent बनाता हूं। और onCreate() कॉल onActivitySetup() जो initializeInjector() और inject() पर कॉल करता है।

public class MainActivity extends BaseActivity implements MainFragment.OnFragmentInteractionListener, 
     HasComponent<FragmentComponent> { 


    private FragmentComponent fragmentComponent; 
    private Fragment currentFragment; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     if (savedInstanceState == null) { 
      currentFragment = new MainFragment(); 
      addFragment(R.id.fragmentContainer, currentFragment); 
     } 

    } 


    private void initializeInjector() { 
     this.fragmentComponent = DaggerFragmentComponent.builder() 
       .applicationComponent(getApplicationComponent()) 
       .activityModule(getActivityModule()) 
       .fragmentModule(getFragmentModule()) 
       .build(); 
    } 

    @Override 
    protected void onActivitySetup() { 
     this.initializeInjector(); 
     fragmentComponent.inject(this); 

    } 

    @Override 
    public void onFragmentInteraction(final Uri uri) { 

    } 

    @Override public FragmentComponent getComponent() { 
     return fragmentComponent; 
    } 


    public FragmentModule getFragmentModule() { 
     return new FragmentModule(currentFragment); 
    } 
} 

यह ठीक काम करता है। और मेरा MainActivityTest भी ठीक काम करता है। यह नाम के टाइपिंग का परीक्षण करता है और निम्न बटन क्लिक का परिणाम क्लिक करता है। लेकिन TextView "हैलो जॉन" दिखाता है।

public class MainActivityTest implements HasComponent<TestFragmentComponent> { 

    @Rule 
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class, true, true); 

    private MainActivity mActivity; 
    private TestFragmentComponent mTestFragmentComponent; 


    @Before 
    public void setUp() throws Exception { 
     mActivity = mActivityRule.getActivity(); 
    } 

    @Test 
    public void testMainFragmentLoaded() throws Exception { 
     mActivity = mActivityRule.getActivity(); 
     assertTrue(mActivity.getCurrentFragment() instanceof MainFragment); 
    } 

    @Test 
    public void testOnClick() throws Exception { 
     onView(withId(R.id.edittext)).perform(typeText("John")); 
     onView(withId(R.id.button)).perform(click()); 
     onView(withId(R.id.textview_greeting)).check(matches(withText(containsString("Hello John")))); 

    } 


    @Override 
    public TestFragmentComponent getComponent() { 
     return mTestFragmentComponent; 
    } 
} 

लेकिन जैसा कि मैंने कहा कि मैं FakeMainInteractor जो मुद्रित होगा "नमस्ते नकली व्यक्ति" का उपयोग करना चाहते। लेकिन मुझे नहीं पता कि टेस्ट के भीतर निर्भरता ग्राफ कैसे बनाया जाए। तो परीक्षण मोड में मैं मूल घटक और मॉड्यूल के बजाय TestComponents और TestModules का उपयोग करके एक और ग्राफ बनाना चाहता हूं। तो यह कैसे करें? परीक्षण FakeMainInteractor का उपयोग कैसे करें?

जैसा कि मैंने बताया, मुझे पता है कि यह उदाहरण ऐप कुछ भी उपयोगी नहीं करता है। लेकिन मैं डैगर 2 के साथ परीक्षण समझना चाहता हूं। मैंने पहले ही this आलेख पढ़ा है। लेकिन यह सिर्फ टेस्टकंपोनेंट्स और टेस्टमोड्यूल बनाने का तरीका दिखाता है। यह यूनिट टेस्ट में टेस्ट-ग्राफ का उपयोग करने का तरीका नहीं बताता है। उसको कैसे करे? क्या कोई कुछ उदाहरण कोड प्रदान कर सकता है?

This मेरे लिए एक समाधान है, क्योंकि यह का उपयोग करता है और डैगर 2 (मैं संस्करण 2.7 का उपयोग करें) के पुराने संस्करण है और यह TestComponents तार करने के लिए कैसे का वर्णन नहीं करता नहीं है।

@Override 
public void setFragmentComponent(final FragmentComponent fragmentComponent) { 
    Log.w(TAG, "Only call this method to swap test doubles"); 
    this.fragmentComponent = fragmentComponent; 
} 

AndroidApplication मालिक:

public void setApplicationComponent(ApplicationComponent applicationComponent) { 
    Log.w(TAG, "Only call this method to swap test doubles"); 
    this.applicationComponent = applicationComponent; 
} 
+0

परीक्षण के लिए डैगर का उपयोग नहीं किया जाता है। आपको पहले डीआई का उपयोग करने के लिए अपनी कक्षाओं को आर्किटेक्चर करना होगा, जिनके पास निर्भरता के नकली/झुंडों के साथ कक्षा को परीक्षण करना आसान बनाने का अच्छा दुष्प्रभाव होता है। आप या तो निर्भरता को मैन्युअल रूप से नया बना सकते हैं या एक मॉकिंग फ्रेमवर्क का उपयोग कर सकते हैं। – Nkosi

+0

मेरा आर्किटेक्चर पहले से ही डी के लिए तैयार है। मैं सिर्फ टेस्ट केस में आर्किटेक्चर लागू नहीं कर सकता। "मैन्युअल रूप से नई निर्भरता" का क्या मतलब है? – unlimited101

+0

आप 'FakeMainInteractor' का एक नया उदाहरण बनाते हैं और इसे तुरंत चालू करते समय परीक्षण में सिस्टम में इंजेक्ट करते हैं। इसके अलावा आपके नकली और ठोस कार्यान्वयन को एक सामान्य अमूर्तता साझा करना चाहिए। – Nkosi

उत्तर

2

आप

public class MainActivityTest{ 

    @Rule 
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule(MainActivity.class, true, true); 

    private MainActivity mActivity; 
    private TestApplicationComponent mTestApplicationComponent; 
    private TestFragmentComponent mTestFragmentComponent; 

    private void initializeInjector() { 
     mTestApplicationComponent = DaggerTestApplicationComponent.builder() 
       .applicationModule(new ApplicationModule(getApp())) 
       .build(); 

     getApp().setApplicationComponent(mTestApplicationComponent); 

     mTestFragmentComponent = DaggerTestFragmentComponent.builder() 
       .testApplicationComponent(mTestApplicationComponent) 
       .activityModule(mActivity.getActivityModule()) 
       .testInteractorModule(new TestInteractorModule()) 
       .build(); 

     mActivity.setFragmentComponent(mTestFragmentComponent); 

     mTestApplicationComponent.inject(this); 
     mTestFragmentComponent.inject(this); 

    } 

    public AndroidApplication getApp() { 
     return (AndroidApplication) InstrumentationRegistry.getInstrumentation().getTargetContext().getApplicationContext(); 
    } 

    @Before 
    public void setUp() throws Exception { 
     mActivity = mActivityRule.getActivity(); 
     initializeInjector(); 
    } 

    @Test 
    public void testMainFragmentLoaded() throws Exception { 
     mActivity = mActivityRule.getActivity(); 
     assertTrue(mActivity.getCurrentFragment() instanceof MainFragment); 
    } 

    @Test 
    public void testOnClick() throws Exception { 
     onView(withId(R.id.edittext)).perform(typeText("John")); 
     onView(withId(R.id.button)).perform(click()); 
     onView(withId(R.id.textview_greeting)).check(matches(withText(containsString("Hello John")))); 
    } 

} 

MainActivity निम्नलिखित नई विधि का मालिक:

@DavidRawson द्वारा दृष्टिकोण की कोशिश के बाद मेरी वर्ग के कुछ उनके कार्यान्वयन बदलमें एक सेटर विधि लिख सकते हैंजड़ Component

ओवरराइड करने के लिए इस विधि जोड़कर अपने वर्तमान Application वर्ग संशोधित करें:

public class AndroidApplication extends Application { 

    @VisibleForTesting 
    public void setApplicationComponent(ApplicationComponent applicationComponent) { 
     Log.w(TAG, "Only call this method to swap test doubles"); 
     this.applicationComponent = applicationComponent; 
    } 
} 

अब अपने परीक्षण सेटअप विधि में, आप असली जड़ Component नकली एक के साथ स्वैप कर सकते हैं:

@Before 
public void setUp() throws Exception { 
    TestApplicationComponent component = 
     DaggerTestApplicationComponent.builder() 
     .applicationModule(new TestApplicationModule()).build(); 

    getApp().setComponent(component); 

} 

private AndroidApplication getApp() { 
    return (AndroidApplication) InstrumentationRegistry.getInstrumentation() 
     .getTargetContext().getApplicationContext(); 
} 

यदि आप निर्भर उपमहाद्वीपों का उपयोग कर रहे हैं, तो आपको शायद अपने BaseActivity के अंदर setComponent नामक एक विधि लिखनी होगी। कृपया ध्यान दें कि सार्वजनिक गेटर्स और सेटर्स जोड़ना, सामान्य रूप से खराब ओओ डिज़ाइन अभ्यास हो सकता है लेकिन यह वर्तमान में डैगर 2 का उपयोग करके हेमेटिक परीक्षण करने के लिए सबसे आसान समाधान है। इन विधियों को here दस्तावेज किया गया है।

+1

क्या 'setAplicationComponent()' वास्तव में 'एप्लिकेशनकंपेंटेंट' वापस करने की आवश्यकता है 'या यह' शून्य 'होना चाहिए? –

+0

ओह - अच्छा स्पॉटिंग! मैं इसे –

+0

@ डेविड रॉसन धन्यवाद दूंगा, जो बहुत मदद करता है। लेकिन दुर्भाग्य से परीक्षण अभी भी 'FakeMainInteractor' के बजाय' MainInteractor' का उपयोग करता है, हालांकि मैंने इसे 'setComponent' विधियों को लागू और बुलाया है। मुझे लगता है कि 'AndroidAplication' और 'MainActivity 'के भीतर टेस्टकंपोनेंट्स द्वारा घटक ओवरराइट किए जाते हैं लेकिन फिर भी मूल को इंजेक्शन दिया जाता है। मैंने अपनी पोस्ट में नवीनतम संपादन संलग्न किया है। – unlimited101

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