翻譯Dagger 2與測試

官方文檔鏈接:https://google.github.io/dagger/testing.html

1.前言


官網(wǎng)上還有篇關(guān)于Java中異步地依賴注入的文章浊服,由于得引入Guava包蜻韭,感覺Android上不太常用儡遮,所以沒有翻譯。若后期項目需要姻几,會再來翻譯的索烹。

使用像Dagger之類的依賴注入框架的好處之一屠列,是它讓代碼測試更簡單。下面探討一些測試Dagger構(gòu)建的應(yīng)用的方法罢艾。

2.單元測試不要使用Dagger


如果想要寫個小的單元測試來測試@Inject注解的類楣颠,其實不需要使用Dagger。僅需調(diào)用@Inject注解的構(gòu)造方法咐蚯、設(shè)置@Inject注解的屬性和調(diào)用需測試的方法童漩,如果可以,直接傳遞假的模擬的依賴項春锋。

final class ThingDoer {
  private final ThingGetter getter;
  private final ThingPutter putter;

  @Inject ThingDoer(ThingGetter getter, ThingPutter putter) {
    this.getter = getter;
    this.putter = putter;
  }

  String doTheThing(int howManyTimes) { /* … */ }
}

public class ThingDoerTest {
  @Test
  public void testDoTheThing() {
    ThingDoer doer = new ThingDoer(fakeGetter, fakePutter);
    assertEquals("done", doer.doTheThing(5));
  }
}

3.替換依賴數(shù)據(jù)


功能睁冬、集成、端到端測試通常用于產(chǎn)線應(yīng)用看疙,用假的(在大型功能測試中不使用模擬的)數(shù)據(jù)替換持久化豆拨、后端和認證系統(tǒng)的數(shù)據(jù),使應(yīng)用的剩余部分能正常工作能庆。這種方法在測試配置替換產(chǎn)品配置中的一些數(shù)據(jù)時施禾,有助于掌控一個(也許少量的)測試配置項

選項1:通過子類Module重寫依賴項(不建議)

在測試Component中搁胆,替換依賴項最簡單的辦法就是通過子類重寫Module里@Provides注解的方法弥搞。(后面會講到存在的問題。)當創(chuàng)建Component的實例渠旁,傳入它需使用的Module對象攀例。(可以但不需要傳入這樣的Module對象,有無參構(gòu)造方法都是靜態(tài)方法 顾腊。)這意味著可以傳入那些Module子類的對象粤铭,而且那些子類可以重寫一些@Provides注解的方法來替換依賴項。

@Component(modules = {AuthModule.class, /* … */})
interface MyApplicationComponent { /* … */ }

@Module
class AuthModule {
  @Provides AuthManager authManager(AuthManagerImpl impl) {
    return impl;
  }
}

class FakeAuthModule extends AuthModule {
  @Override
  AuthManager authManager(AuthManagerImpl impl) {
    return new FakeAuthManager();
  }
}

MyApplicationComponent testingComponent = DaggerMyApplicationComponent.builder()
    .authModule(new FakeAuthModule())
    .build();

但這種方法有些局限性:
第一杂靶,使用Module的子類不能改變依賴圖內(nèi)的關(guān)系:不能增加梆惯、刪除或更改依賴。尤其是:

  • 重寫@Provides注解的方法不能更改它參數(shù)類型吗垮,且縮小范圍的返回類型對Dagger而言并不影響依賴圖垛吗。在上面的例子中,testingComponent對象需要的仍然是AuthManagerImpl和它相關(guān)的依賴烁登,即使它們沒有被使用怯屉。
  • 同樣的,重寫Module不能給依賴圖增加關(guān)系,包括新的多元綁定(即使仍然能重寫SET_VALUES方法返回不同的Set)锨络。子類中任何新的@Provides注解的方法都默認被Dagger忽略赌躺。實際上,可理解為假的依賴項欺騙不了依賴注入足删。

第二寿谴,這種方式下,可重寫的@Provides注解的方法不可能是靜態(tài)的失受,所以它們Module對象不能被忽略讶泰。

選項2:分開配置Component

另一種方法要求應(yīng)用中有更多預(yù)設(shè)的Module。產(chǎn)線應(yīng)用中的每個配置拂到,都得在測試Component中進行不同的配置痪署。測試Component類繼承自產(chǎn)線Component類,而且添加一系列不同的Module兄旬。

@Component(modules = {
  OAuthModule.class, // real auth
  FooServiceModule.class, // real backend
  OtherApplicationModule.class,
  /* … */ })
interface ProductionComponent {
  Server server();
}

@Component(modules = {
  FakeAuthModule.class, // fake auth
  FakeFooServiceModule.class, // fake backend
  OtherApplicationModule.class,
  /* … */})
interface TestComponent extends ProductionComponent {
  FakeAuthManager fakeAuthManager();
  FakeFooService fakeFooService();
}

測試時狼犯,調(diào)用DaggerTestComponent.builder()取代DaggerProductionComponent.builder()作為Main方法。注意领铐,測試Component接口可以增加預(yù)定的對假數(shù)據(jù)的處理(fakeAuthManager()fakeFooService())悯森,那樣必要情況下,可在測試中訪問它們來掌控數(shù)據(jù)绪撵。

下面來講一講如何設(shè)計Module來簡化這個模式瓢姻。

4.可測試的模塊設(shè)計


Module類是一種工具類:包含單獨的@Provides注解的方法的集合,里面每個方法都可能被用來給應(yīng)用注入需要的一些類型音诈。(雖然幾個@Provides注解的方法可能相關(guān)聯(lián)幻碱,一個依賴另一個提供的類型,它們通常不會顯示調(diào)用彼此依賴相同的可變狀態(tài)细溅。一些@Provides注解的方法引用相同的屬性對象褥傍,這樣的話它們實際并不獨立。這里給點建議喇聊,無論如何要像對待工具方法一樣對待@Provides注解的方法恍风,因為它使Module在測試時更容易被替換。)

那么如何決定哪些@Provides注解的方法應(yīng)該放在一個Module類中承疲?

一方面考慮到將依賴劃分為公開的和內(nèi)部的邻耕,然后進一步考慮公開的依賴是否有合理的替代方案。

  • 公開的依賴是那些提供功能的燕鸽、被應(yīng)用其它部分使用的。像AuthManager或User或DocDatabase這些類型是公開的:在Module中聲明啼辣,應(yīng)用其它部分可以使用它們啊研。
  • 內(nèi)部的依賴是除公開依賴之外的:被用來實現(xiàn)一些公開的類型,除了作為它的一部分,并不一定要被使用党远。舉個例子削解,配置認證客戶端ID或OAuthKeyStore的依賴打算只在AuthManager實現(xiàn)認證的時候使用,而不是應(yīng)用的其它部分沟娱。這些依賴通常是包內(nèi)私有類型或被包內(nèi)私有限定符修飾氛驮。

這些公開的依賴將有合理的替代方案,主要用于測試济似,其它情況則不用矫废。舉個例子,像AuthManager這類型的替代依賴項:一個用于測試砰蠢,其它用于不同的認證/授權(quán)協(xié)議蓖扑。

另一方面,如果AuthManager接口有個方法返回當前登錄的用戶台舱,可能想要簡單調(diào)用AuthManager的getCurrentUser()方法提供User的公開依賴律杠。這種公開的依賴不太可能需要替代方案。

一旦劃分為帶合理替代方案的公開依賴竞惋、不帶合理替代方案的公開依賴和內(nèi)部依賴柜去,可以考慮這樣安排它們到Module中:

  • 為每個帶合理替代方案的公開依賴提供Module。這Module顯示包含一個公開的依賴拆宛,以及它需要的所有的內(nèi)部依賴嗓奢。
  • 所有不帶合理替代方案的公開依賴按照功能的順序放入Module中。
  • 每個公開依賴的Module應(yīng)該包含需被提供公開依賴的不帶合理替代方案的模塊胰挑。

通過描述提供的公開依賴來記錄每個Module是個好的主意蔓罚。這有個認證相關(guān)的例子。有個AuthManager接口及兩個實現(xiàn)瞻颂,一個實現(xiàn)有認證邏輯豺谈,另一個假的實現(xiàn)用于測試。產(chǎn)線配置將使用真實的Module贡这,而測試配置假的Module茬末。同上,還有個不期望隨著配置改變的關(guān)于當前用戶的顯式依賴盖矫。

/**
 * Provides auth bindings that will not change in different auth configurations,
 * such as the current user.
 */
@Module
class AuthModule {
  @Provides static User currentUser(AuthManager authManager) {
    return authManager.currentUser();
  }
  // Other bindings that don’t differ among AuthManager implementations.
}

/** Provides a {@link AuthManager} that uses OAuth. */
@Module(includes = AuthModule.class) // Include no-alternative bindings.
class OAuthModule {
  @Provides static AuthManager authManager(OAuthManager authManager) {
    return authManager;
  }
  // Other bindings used only by OAuthManager.
}

/** Provides a fake {@link AuthManager} for testing. */
@Module(includes = AuthModule.class) // Include no-alternative bindings.
class FakeAuthModule {
  @Provides static AuthManager authManager(FakeAuthManager authManager) {
    return authManager;
  }
  // Other bindings used only by FakeAuthManager.
}

5.總結(jié)


關(guān)于Dagger 2的常見使用丽惭,到此算是翻譯結(jié)束了。通過這段時間的學(xué)習(xí)辈双,覺得Dagger 2對于代碼的拆解和封裝有很大的幫助责掏,可以大大簡化代碼,突出體現(xiàn)業(yè)務(wù)邏輯湃望,降低了應(yīng)用的耦合性换衬。歡迎大家在使用的同時痰驱,將心得體會與我交流,在此感謝瞳浦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末担映,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叫潦,更是在濱河造成了極大的恐慌蝇完,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矗蕊,死亡現(xiàn)場離奇詭異短蜕,居然都是意外死亡,警方通過查閱死者的電腦和手機拔妥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門忿危,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人没龙,你說我怎么就攤上這事铺厨。” “怎么了硬纤?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵解滓,是天一觀的道長。 經(jīng)常有香客問我筝家,道長洼裤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任溪王,我火速辦了婚禮腮鞍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘莹菱。我一直安慰自己移国,他們只是感情好,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布道伟。 她就那樣靜靜地躺著迹缀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜜徽。 梳的紋絲不亂的頭發(fā)上祝懂,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機與錄音拘鞋,去河邊找鬼砚蓬。 笑死,一個胖子當著我的面吹牛盆色,可吹牛的內(nèi)容都是我干的怜械。 我是一名探鬼主播呢堰,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼野芒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掂恕?” 一聲冷哼從身側(cè)響起蹭越,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤障本,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后响鹃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驾霜,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年买置,在試婚紗的時候發(fā)現(xiàn)自己被綠了粪糙。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡忿项,死狀恐怖蓉冈,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轩触,我是刑警寧澤寞酿,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站脱柱,受9級特大地震影響伐弹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜榨为,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一惨好、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧随闺,春花似錦日川、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至绰精,卻和暖如春撒璧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背笨使。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工卿樱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人硫椰。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓繁调,卻偏偏與公主長得像萨蚕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蹄胰,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354