2016-11-03 40 views
5

Örnek bir uygulama geliştirdim (Evet, bu sadece bir örnek ve pek bir anlam ifade etmiyor, ancak Android temiz mimarisini ve Dagger 2'deki bağımlılık enjeksiyonunu anlamak için iyi). Benim kod github mevcuttur. Örnek uygulama sadece bir EditText bir isim yazın ve tuşuna basınca eğer bir mesaj görüyorum "Merhaba adınız"Dagger 2 Android TestCase'de Bağımlılık Enjeksiyonu

farklı üç tane yapalım (Eski. this yayınlara bakın) Bileşenler: ApplicationComponent, ActivityComponent ve FragmentComponent.

  • ActivityModule
  • FragmentModule

InteractorModule bir MainInteractor sağlar

  • InteractorModule: FragmentComponent üç modülleri içerir. Benim Etkinlik-UnitTest yılında

    @Module 
    public class InteractorModule { 
    
        @Provides 
        @PerFragment 
        MainInteractor provideMainInteractor() { 
         return new MainInteractor(); 
        } 
    } 
    

    Ben sahte bu MainInteractor istiyorum. Bu Interactor sadece bir Person nesnesi oluşturabilen bir public Person createPerson(String name) metoduna sahiptir. FakeMainInteractor aynı yönteme sahiptir, ancak her zaman geçirdiğiniz parametrenin bağımsız olarak "Sahte Kişi" ismiyle bir Kişi nesnesi oluşturur.

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

    Zaten zaten yukarıda açıklanan Bileşen I için TestComponents'ı yaratıyorum. Ve TestFragmentComponent'da InteractorModule'u TestInteractorModule ile değiştirdim.

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

    Bu örnek, test dışı bir bağlamda iyi çalışıyor. MainActivity'da initializeInjector() adlı bir yöntem var ve burada FragmentComponent'u yapıyorum. Ve onCreate(), 'un initializeInjector() ve inject() numaralarını onActivitySetup() çağırır.

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

    Bu iyi çalışıyor. Ve benim MainActivityTest da iyi çalışıyor. Adın yazılmasını ve aşağıdaki düğmenin sonucunu test eder. Ancak TextView “Merhaba John” u gösterir.

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

    Ama “Merhaba Sahte Kişi” yazdırmak istiyorum FakeMainInteractor kullanmak istediğiniz söylediği gibi. Ancak, Test içindeki bağımlılık grafiğini nasıl oluşturacağımı bilmiyorum. Test modunda, orijinal Bileşenler ve Modüller yerine TestComponents ve TestModules kullanılarak başka bir grafik oluşturulmasını istiyorum. Peki bunu nasıl yapmalı? Testin FakeMainInteractor nasıl kullanılmasına izin verilir?

    Söylediğim gibi, bu örnek uygulamanın yararlı bir şey yapmadığını biliyorum. Ama Hançer 2 ile Testi anlamak istiyorum. Zaten this makalesini okudum. Ama sadece TestComponents ve TestModules nasıl yapılır gösterir. Birim Testinde bir Test-Grafiğinin nasıl kullanılacağını anlatmaz. Bu nasıl yapılır? Birisi bir örnek kod sağlayabilir mi? Kullandığı ve Hançer 2 (ı sürüm 2.7 kullanmak) eski sürümü ve TestComponents lantÛlarÛyla açıklanmaz yapar çünkü

    This, benim için bir çözüm değildir.

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

    AndroidApplication sahibi:

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

    Hançer test için kullanılmaz. İlk olarak, sınıflarınızı, sınıfları bağımlılıkların sahte/alaylarıyla test etmeyi kolaylaştıracak iyi yan etkiye sahip olan DI'yi kullanacak şekilde mimarlık yapmak zorundasınız. bağımlılıkları manuel olarak veya alaycı bir çerçeve kullanarak yenileyebilirsiniz. – Nkosi

    +0

    Mimarim zaten DI için hazır. Mimariyi test vakasına uygulayamıyorum. Tam olarak "bağımlılıkları el ile yeni" ile ne demek istiyorsun? – unlimited101

    +0

    , "FakeMainInteractor" ın yeni bir örneğini oluşturup, bunu başlatırken sınanacak sisteme enjekte edersiniz. Ayrıca sahte ve somut uygulamalarınız ortak bir soyutlamayı paylaşmalıdır. – Nkosi

    cevap

    2

    You

    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 aşağıdaki yeni yöntem sahibi:

    @DavidRawson tarafından yaklaşımını denedikten sonra bazı sınıfların bunların uygulanmasını değiştirdi’da setter metodu yazabilir

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

    şimdi test kurulum yönteminde, sahte biriyle gerçek kök Component takas edebilirsiniz:

    bu yöntemi ekleyerek mevcut Application sınıf değiştirme kök Component

    geçersiz kılmak için

    Bağımlı alt bileşenler kullanıyorsanız, muhtemelen BaseActivity içinde setComponent adlı bir yöntem yazmanız gerekecektir. Genel olarak, alıcılar ve ayarlayıcıların genel olarak kötü bir OO tasarım uygulaması olabileceğini unutmayın, ancak bu, Hançer 2'yi kullanarak hermetik testlerin gerçekleştirilmesi için en basit çözümdür. Bu yöntemler, here belgelenmiştir.

    +1

    'setApplicationComponent()' 'gerçekten de' ApplicationComponent 'döndürmesi gerekiyor mu? ya da 'void' olmalı? –

    +0

    oops - iyi lekelenme! Düzelteceğim –

    +0

    @DavidRawson Teşekkürler, bu çok yardımcı olur. Ama ne yazık ki, bu "setComponent" yöntemlerini uygulamış ve çağırmış olsam da, test hala "FakeMainInteractor" yerine "MainInteractor" kullanıyor. Ne düşündüğüm Bileşenleri 'AndroidApplication' ve 'MainActivity' içinde TestComponents tarafından üzerine yazılır ama hala orijinalleri enjekte edilir. Bu yeni düzenlemeyi gönderime ekledim. – unlimited101

    İlgili konular