मैंने एक उदाहरण एप्लिकेशन बनाया है (हां, यह वास्तव में केवल एक उदाहरण है और यह बहुत समझ में नहीं आता है लेकिन एंड्रॉइड क्लीन आर्किटेक्चर और डैगर 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;
}
परीक्षण के लिए डैगर का उपयोग नहीं किया जाता है। आपको पहले डीआई का उपयोग करने के लिए अपनी कक्षाओं को आर्किटेक्चर करना होगा, जिनके पास निर्भरता के नकली/झुंडों के साथ कक्षा को परीक्षण करना आसान बनाने का अच्छा दुष्प्रभाव होता है। आप या तो निर्भरता को मैन्युअल रूप से नया बना सकते हैं या एक मॉकिंग फ्रेमवर्क का उपयोग कर सकते हैं। – Nkosi
मेरा आर्किटेक्चर पहले से ही डी के लिए तैयार है। मैं सिर्फ टेस्ट केस में आर्किटेक्चर लागू नहीं कर सकता। "मैन्युअल रूप से नई निर्भरता" का क्या मतलब है? – unlimited101
आप 'FakeMainInteractor' का एक नया उदाहरण बनाते हैं और इसे तुरंत चालू करते समय परीक्षण में सिस्टम में इंजेक्ट करते हैं। इसके अलावा आपके नकली और ठोस कार्यान्वयन को एक सामान्य अमूर्तता साझा करना चाहिए। – Nkosi