2016-11-05 39 views
5

我有一個Presenter類使用通過注射匕首一個字段,它看起來是這樣的:單位懲戒注入實地測試

public class RssListPresenter { 

    @Inject 
    RssService rssService; // <-- injected field 

    public RssListPresenter() { 
     setupDI(); 
    } 

    private void setupDI() { 
     DaggerNetworkComponent.builder() 
       .networkModule(new NetworkModule()) 
       .build() 
       .inject(this); 
    } 

    public void loadItems() { 
     Rss rss = rssService.getRssFeed() 
     // .... 
    } 
} 

,一切工作正常。現在,我想單元測試RssListPresenter班。問題是如何向演示者提供模擬RssService

Ofcourse我可以添加一個新的方法setRssService(RssService rssService)給主持人,並用它來提供從單元測試的模擬,但僅僅爲單元測試添加此方法感覺不對。處理這個問題的正確方法是什麼?

爲了完整這裏的模塊和組件聲明:

@Singleton 
@Component(modules = NetworkModule.class) 
public interface NetworkComponent { 
    void inject(RssListPresenter presenter); 
} 

@Module 
public class NetworkModule { 

    @Provides 
    Retrofit provideRetrofit() { 
     // ... 
    } 

    @Provides 
    @Singleton 
    RssService providePcWorldRssService(Retrofit retrofit) { 
     return retrofit.create(RssService.class); 
    } 

} 
+0

一次:當你沒有單元測試,但你怎麼知道它工作正常?第二:這個字段既不是'private'也不是'final',所以你可以簡單地從你的TestClass中設置它(如果它在同一個包中)。 –

+0

1 - 您運行該應用程序,並且當該字段未被注入時,您會立即看到結果:),2 - 我認爲我將按照以下建議與施工注射一起去,但也要感謝您的建議。 –

+0

*「,當字段沒有被注入時,你會立即看到結果:)」* OK,但是這是「DI框架工程」,這不是我對「一切正常」的理解,其中包括* my的實際行爲*代碼,而不是任何框架的代碼。這就是爲什麼我問......; o) –

回答

5

物業注射就是這樣也不是那麼容易測試。在這種情況下,構造函數注入要好得多。重構你的構造,看起來像這樣:

private final RssService rssService; 

@Inject 
public RssListPresenter(RssService rssService) { 
     this.rssService = rssService; 
} 

現在你可以很容易地測試它:

//mocks 
RssService mockRssService; 

//system under test 
RssListPresenter rssListPresenter; 

@Before 
public void setup() { 
    mockRssService = Mockito.mock(RssService.class); 
    rssListPresenter = new RssListPresenter(mockRssService); 
} 

你可能不應該使用DaggerNetworkComponent.inject(this)RssListPresenter。相反,您應該配置匕首,以便當它將註冊成員注入頂級類別(ActivityFragmentService)時,它可以訪問對象圖並創建RssPresenter的實例。

爲什麼只把噴油器放在ActivityService而不是像RssListPresenter之類的東西?這些是由Android系統實例化的類,因此您別無選擇,只能使用注入器。

澄清,ActivityFragment等是理想的注射目標RssListPresenter等都是注入依賴關係。您需要配置依賴關係注入框架匕首,以便它可以提供正確的依賴關係以注入注入目標。

所以,你還需要編寫一個@Provides方法RssListPresenter

@Provides provideRssListPresenter(RssService rssService) { 
    return new RssListPresenteR(rssService); 
} 
+0

謝謝你的詳細解釋和例子! –

+0

如果他添加另一個僅將RssService參數用於測試目的的構造函數,會發生什麼情況? –

+1

@NikolaDespotoski不知道你爲什麼想這樣做。你想要設計你的類,使它們很乾淨,不必爲了測試而改變它們,對嗎? –

0

你的類違犯了一些S.O.L.I.D原則,這使得單元測試是很困難的。您的班級確實違反了SRP(單一責任原則),因爲它有多個的原因發生變化。還有可能存在依賴性反轉違規。

我建議重新考慮類的模型,以便每個類都執行特定的功能,並有一個改變的原因。