Android mock for循环,Android单元测试(五):依赖注入,将mock方便的用起来
在上一篇文章中,咱們講了要將mock出來的dependency真正使用起來,須要在測試環境下經過某種方式set 到用到它的那個對象里面進去,替換掉真實的實現。咱們前面舉的例子是:html
public class LoginPresenter {
private UserManager mUserManager = new UserManager();
public void login(String username, String password) {
//。。。some other code
mUserManager.performLogin(username, password);
}
}
在測試LoginPresenter#login()時,為了可以將mock出來的UserManager set到LoginPresenter里面,咱們前面的作法是簡單粗暴,給LoginPresenter加一個UserManager的setter。然而這種作法畢竟不是很優雅,通常來講,咱們正式代碼里面是不會去調用這個setter,修改UserManager這個對象的。所以這個setter存在的意義就純粹是為了方便測試。這個雖然不是沒有必要,卻不是太好看,所以在有選擇的狀況下,咱們不這么作。在這里,咱們介紹依賴注入這種模式。java
對于依賴注入(Dependency Injection,如下簡稱DI)的準肯定義能夠在這里找到。它的基本理念這邊簡單描述下,首先這是一種代碼模式,這個模式里面有兩個概念:Client和Dependency。假如你的代碼里面,一個類用到了另一個類,那么前者叫Client,后者叫Dependency。結合上面的例子,LoginPresenter用到了UserManager,那么LoginPresenter叫Client,UserManager叫Dependency。固然,這是個相對的概念,一個類能夠是某個類的Dependency,倒是另一個類的Client。好比說若是UserManager里面用到了Retrofit,那么相對于Retrofit,UserManager又是Dependency。DI的基本思想就是,對于Dependency的建立過程,并不在Client里面進行,而是由外部建立好,而后經過某種方式set到Client里面。這種模式,就叫作依賴注入。android
是的,依賴注入就是這么簡單的一個概念,這邊須要澄清的一點是,這個概念自己跟dagger2啊,RoboGuice這些框架并無什么關系。如今不少介紹DI的文章每每跟dagger2是在一塊兒的,由于dagger2的使用相對來講不是很直觀,因此致使不少人認為DI是多么復雜的東西,甚至認為只能用dagger等框架來實現依賴注入,其實不是這樣的。實現依賴注入很簡單,dagger這些框架只是讓這種實現變得更加簡單,簡潔,優雅而已。git
DI的常見實現方式
下面介紹DI的實現方式,一般來講,這里是大力介紹dagger2的地方。可是,雖然dagger2的確是很是好的東西,然而若是我直接介紹dagger2的話,會很容易致使一個誤區,認為在測試的時候,也只能用dagger來作依賴注入或建立對應的測試類,所以,我這邊刻意不介紹dagger。先讓你們知道最基本的DI怎么實現,而后在測試的時候如何更方便高效的使用。github
實現DI這種模式其實很簡單,有多種方式,上一篇文章中提到的setter,其實就是實現DI的一種方式,叫作 setter injection 。此外,經過方法的參數傳遞進去(argument injection),也是實現DI的一種方式:框架
public class LoginPresenter {
//這里,LoginPresenter再也不持有UserManager的一個引用,而是做為方法參數直接傳進去
public void login(UserManager userManager, String username, String password) {
//... some other code
userManager.performLogin(username, password);
}
}
然而更經常使用的方式,是將Dependency做為Client的構造方法的參數傳遞進去:單元測試
public class LoginPresenter {
private final UserManager mUserManager;
//將UserManager做為構造方法參數傳進來
public LoginPresenter(UserManager userManager) {
this.mUserManager = userManager;
}
public void login(String username, String password) {
//... some other code
mUserManager.performLogin(username, password);
}
}
這種實現DI的模式叫 Constructor Injection。其實通常來講,提到DI,指的都是這種方式。這種方式的好處是,依賴關系很是明顯。你必須在建立這個類的時候,就提供必要的dependency。這從某種程度上來講,也是在說明這個類所完成的功能。所以,盡可能使用 Constructor injection。測試
說到這里,你可能會有一個疑問,若是把依賴都聲明在Constructor的參數里面,這會不會讓這個類的Constructor參數變得很是多?若是真的發生這種狀況了,那每每說明這個類的設計是有問題的,須要重構。為何呢?咱們代碼里面的類,通常能夠分為兩種,一種是Data類,好比說UserInfo,OrderInfo等等。另一種是Service類,好比UserManager, AudioPlayer等等。因此這個問題就有兩種狀況了:ui
若是Constructor里面傳入的不少是基本類型的數據或數據類,那么或許你要作的,是建立一個(或者是另外一個)數據類把這些數據封裝一下,這個過程的價值但是大大滴!而不只僅是封裝一下參數的問題,有了一個類,不少的方法就能夠放到這個類里面了。這點請參考Martin Fowler的《重構》第十章“Introduce Parameter Object”。this
若是傳入的不少是service類,那么這說明這個類作的事情太多了,不符合單一職責的原則(Single Responsibility Principle,SRP),所以,須要重構。
接下來講回咱們的初衷:DI在測試里面的應用。
DI在單元測試里面的應用
所謂DI在單元測試里面的應用,其實說白了就是使用DI模式,將mock出來的Dependency set到Client里面去。我相信這篇文章解釋到這里,那么答案也就比較明顯了,為了強調咱們要盡可能使用 Constructor injection,對于 setter Injection 和 Argument injection 這邊就不作代碼示例了。
若是你的代碼使用的是 Constructor injection:
public class LoginPresenter {
private final UserManager mUserManager;
//將UserManager做為構造方法參數傳進來
public LoginPresenter(UserManager userManager) {
this.mUserManager = userManager;
}
public void login(String username, String password) {
//... some other code
mUserManager.performLogin(username, password);
}
}
其中咱們要測的方法是login(), 要驗證login()方法調用了mUserManager的performLigon()。對應的測試方法以下:
public class LoginPresenterTest {
@Test
public void testLogin() {
UserManager mockUserManager = Mockito.mock(UserManager.class);
LoginPresenter presenter = new LoginPresenter(mockUserManager); //建立的時候,講mock傳進去
presenter.login("xiaochuang", "xiaochuang password");
Mockito.verify(mockUserManager).performLogin("xiaochuang", "xiaochuang password");
}
}
很簡單,對吧。
小結
這篇文章介紹了DI的概念,以及在單元測試里面的應用,這里特地沒有介紹dagger2的使用,目的是要強調:
一個靈活的,易于測試的,符合SRP的,結構清晰的項目,關鍵在于要應用依賴注入這種模式,而不是用什么來作依賴注入。
等你學會使用dagger之后,要記得在測試的時候,若是能夠直接mock dependency并傳給被測類,那就直接建立,不是必定要使用dagger來作DI
然而若是徹底不使用框架來作DI,那么在正式代碼里面就有一個問題了,那就是dependency的建立工做就交給上層client去處理了,這可不是件好事情。想一想看,LoginActivity里面建立LoginPresenter的時候,還得知道LoginPresenter用了UserManager。而后建立一個UserManager對象給LoginPresenter。對于LoginActivity來講,它以為我才懶得管你用什么樣的UserManager呢,我只想告訴你login的時候,你給我老老實實的login就行了,你用什么Manager我無論。因此,直接在LoginActivity里面建立UserManager,可能不是個好的選擇。那怎么樣算是一個好的選擇呢?dagger2給了咱們答案。
因而下一篇文章咱們介紹dagger2。
最后,若是你也對安卓單元測試感興趣的話,歡迎加入咱們的交流群:
總結
以上是生活随笔為你收集整理的Android mock for循环,Android单元测试(五):依赖注入,将mock方便的用起来的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于javaweb的公交查询系统的设计与
- 下一篇: layui结合form,table的全选