[英]What is the best way to inject subclasses using Dagger 2?
我最近開始使用 Dagger 2 來管理我的應用程序的依賴注入。 為了使某些類可測試,我開始創建許多需要注入的類。 我能夠這樣做,但是,注入這些新類的過程對我來說看起來有點復雜。 讓我們舉個例子:
例如,我想測試我的 RecyclerViewAdapter 中的onCreateViewHolder()
方法。 為此,我創建了一個 Factory,它根據給定的 LayoutType 返回 ViewHolder:
public class ViewHolderFactor {
public RecyclerView.ViewHolder getViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = this.getLayoutInflater(parent.getContext());
View view;
switch (LayoutType.fromInteger(viewType)) {
case SMALL_VERTICAL:
view = inflater.inflate(R.layout.rsc_util_item_small, parent, false);
return new ViewHolder.ItemViewHolder(view);
case LARGE_VERTICAL:
view = inflater.inflate(R.layout.rsc_util_item_large, parent, false);
return new ViewHolder.ItemViewHolder(view);
}
return null;
}
private LayoutInflater getLayoutInflater(Context context) {
return LayoutInflater.from(context);
}
}
通過將上面的代碼移動到一個單獨的類,我可以使用以下方法執行我的單元測試:
@RunWith(JUnit4.class)
public class TestViewHolderFactor extends TestCase {
ViewHolderFactor viewHolderFactor;
@Test
public void testGetViewHolder () {
this.viewHolderFactor = Mockito.mock(ViewHolderFactor.class);
ViewGroup viewGroup = Mockito.mock(ViewGroup.class);
Mockito.when(viewHolderFactor.getViewHolder(viewGroup, LayoutType.SMALL_VERTICAL.toInteger())).thenCallRealMethod();
Context context = Mockito.mock(Context.class);
Mockito.when(viewGroup.getContext()).thenReturn(context);
LayoutInflater layoutInflater = Mockito.mock(LayoutInflater.class);
Mockito.when(viewHolderFactor.getLayoutInflater(context)).thenReturn(layoutInflater);
Mockito.when(layoutInflater.inflate(R.layout.rsc_util_item_small, viewGroup, false)).thenReturn(Mockito.mock(View.class));
RecyclerView.ViewHolder result = viewHolderFactor.getViewHolder(viewGroup, LayoutType.SMALL_VERTICAL.toInteger());
assertNotNull(result);
}
}
問題是:現在,為了使應用程序正常工作,我還必須將保存實例的外部類注入到因子(在創建 ViewHolderFactor 之前我沒有做的事情)。 最后,我將有一個這樣的 Dagger 配置:
@Module
public class ModuleBusiness {
@Provides
public CharacterUIService provideCharacterService(Picasso picasso, NotificationUtil notificationUtil, ViewHolderFactor viewHolderFactor) {
return new CharacterUIService(picasso, notificationUtil, viewHolderFactor);
}
}
其中 CharacterUIService 是創建包含 ViewHolderFactory 的 RecyclerViewAdapter 新實例的類。
public class
private ViewHolderFactor
@Inject
public CharacterUIService(ViewHolderFactor viewHolderFactor) {
this.mViewHolderFactor = viewHolderFactor;
}
// ...
}
我需要 ViewHolderFactor 的成員才能注入它。
我擔心需要創建新的全局變量並增加構造函數中傳遞的參數數量。 是否有更好的方法來注入這些子類,或者我可以將其視為允許單元測試的好方法嗎?
我可以將其視為允許單元測試的好習慣嗎?
首先——在我個人看來——我認為你做的測試過度了。 在您提供的測試用例中,您基本上是在測試android 框架本身。 如果要測試工廠,則應測試返回的是小項還是大項,而不是視圖不為空。
但是,是的,您的方法似乎是允許單元測試的合理方法。
其中 CharacterUIService 是創建 RecyclerViewAdapter 新實例的類
您可能想過度考慮CharacterUIService
的作用。 “創建一個新實例”聽起來像是應該由 dagger 處理的東西,因為您已經在使用它了。
還必須將持有實例的外部類注入工廠
為什么? ViewHolderFactor
(原文如此!)本身沒有依賴項。 即使它做到了,是什么阻止你僅僅用匕首創建和注入它?
class ViewHolderFactor {
@Inject
ViewHolderFactor() { // allow for constructor injection
}
}
class YourAdapter {
ViewHolderFactor mFactor;
@Inject // allow for constructor injection
YourAdapter (ViewHolderFactor factor) {/**/}
}
// now dagger knows how to create that adapter
只是創建讓匕首創建該適配器?
通常,如果您支持構造函數注入,那么您可以刪除您的@Provides providesSomething()
方法。 只需刪除整個方法。 您在構造函數上有一個@Inject
注釋,因此請使用它並讓 dagger 為您編寫該代碼。
// CharacterUIService can be constructor injected.
@Provides // DAGGER WILL DO THIS FOR YOU
public CharacterUIService provideCharacterService(Picasso picasso, NotificationUtil notificationUtil, ViewHolderFactor viewHolderFactor) {
// REMOVE ALL OF THIS.
return new CharacterUIService(picasso, notificationUtil, viewHolderFactor);
}
所以雖然我認為你通過使事情可測試做得很好,但你應該再次好好看看 dagger,因為你顯然把很多東西混在一起了。 好好看看構造函數注入並利用它,它可以為您節省大量工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.