簡體   English   中英

android retrofit2,dagger2單元測試

[英]android retrofit2, dagger2 unit test

我學習了如何在android中測試MVP體系結構的presenter層,使用改良版2的演示者,在我的活動中,我使用dagger 2作為對演示者的依賴注入,這是我的Dagger和presenter注入看起來像:

@Inject
AddScreenPresenter addScreenPresenter;

這是Dagger構建器:

DaggerAddScreenComponent.builder()
            .netComponent(((App) getApplicationContext()).getNetComponent())
            .addScreenModule(new AddScreenModule(this, new ContactDatabaseHelper(this)))
            .build().inject(this);

這是我的主持人構造函數:

@Inject
public AddScreenPresenter(Retrofit retrofit, AddScreenContact.View view, ContactDatabaseHelper contactDatabaseHelper)
{
    this.retrofit = retrofit;
    this.view = view;
    this.contactDatabaseHelper = contactDatabaseHelper;
}

我已經編寫了單元測試類並模擬了Retrofit類,但是當我運行它時,出現了錯誤:

Mockito cannot mock/spy following:

-最終課程-匿名課程-基本類型

這是測試類:

@RunWith(MockitoJUnitRunner.class)
public class AddScreenPresenterTest {

private AddScreenPresenter mAddPresenter;

@Mock
private Retrofit mRetrofit;

@Mock
private Context mContext;

@Mock
private AddScreenContact.View mView;

@Mock
private ContactDatabaseHelper mContactDatabaseHelper;


String firstName, phoneNumber;

Upload upload;


@Before
public void setup() {
    mAddPresenter = new AddScreenPresenter(mRetrofit, mView, mContactDatabaseHelper);

    firstName = "aFirstName";

    phoneNumber = "998012341234";

    Uri path = Uri.parse("android.resource://"+BuildConfig.APPLICATION_ID+"/" + R.drawable.missing);

    upload = new Upload();
    upload.title = firstName;
    upload.description = "aDescription";
    upload.albumId = "XXXXX";
    upload.image = new File(path.getPath());
}

@Test
public void checkValidationTest() {
    verify(mAddPresenter).checkValidation(firstName, phoneNumber);
}


@Test
public void uploadMultiPartTest() {
    verify(mAddPresenter).uploadMultiPart(upload);
}

}

這是我的模塊:

@Module
public class AddScreenModule {

private final AddScreenContact.View mView;
private final ContactDatabaseHelper mContactDatabaseHelper;

public AddScreenModule (AddScreenContact.View view, ContactDatabaseHelper contactDatabaseHelper)
{
    this.mView = view;
    this.mContactDatabaseHelper = contactDatabaseHelper;
}

@Provides
@CustomScope
AddScreenContact.View providesAddScreenContactView() {
    return mView;
}

@Provides
@CustomScope
ContactDatabaseHelper providesContactDatabaseHelper() {
    return mContactDatabaseHelper;
}
}

我知道Retrofit類是最后一個類,現在我陷入困境,不知道如何在測試類中創建Presenter對象。 請幫助我,如何在構造函數中通過改造來創建presenter類的對象。 隨時問我的問題是否還不夠清楚,非常感謝您的幫助。

個人而言,我會做主持人不依賴於Retrofit類,而是由創建的服務Retrofit -這些都是mockable。

從您發布的代碼中很難說出您的演示者實際使用的服務,但是為了簡單起見,我們假設它僅使用一個,並假設它是AddsService這是一個可以與Retrofit一起使用的接口。 像這樣的東西

public interface AddsService {
   @GET(...)
   Call<List<Adds>> getAllAdds();
}

現在,您可以使演示者依賴於此而不是Retrofit

@Inject
public AddScreenPresenter(AddsService addsService, 
                          AddScreenContact.View view, 
                          ContactDatabaseHelper contactDatabaseHelper){
   this.addsService = addsService;
   this.view = view;
   this.contactDatabaseHelper = contactDatabaseHelper;
}

現在,您需要提供此依賴性。 我猜你也有一個NetModule ,因為你有一個NetComponent ,所以我想你可以這樣做:

@Module
public class NetModule {
   // Methods providing Retrofit
   @Provides
   @Singleton
   public AddsService providesAddsService(Retrofit retrofit) {
      return retrofit.create(AddsService.class);
   }
}

注意如何providesAddsService取決於改造? 由於您的演示者依賴於此,因此應該已經提供了。 您不需要為此做任何更改。 匕首是能夠找出如何提供Retrofit的方法providesAddsService

另請注意,我假設您可以在Singleton范圍內提供這些功能。 我之所以這樣認為是因為在您的代碼中,您從應用程序中檢索了組件,該組件應處理單例作用域。

現在,在您的測試中,您可以簡單地模擬AddsService並測試演示者。

如果您的演示者需要更多服務,我還將在構造函數中傳遞它們,並為Dagger提供實現。

另外,我還想說一下,改造實例和改造服務僅應創建一次(或至少創建次數最少)。 這是因為它們通常是昂貴的操作,並且您通常總是使用不同的參數查詢相同的端點。

編輯

回答評論中的一些問題。 首先簡單一點:如何在測試類中創建演示者? 像您一樣,我也嘗試在測試期間擺脫Dagger的原因,這就是為什么我更喜歡構造函數依賴項注入,就像您正在使用的那樣。 因此,在我的測試課中,我會有類似你的東西:

@RunWith(MockitoJUnitRunner.class)
public class AddScreenPresenterTest {

   private AddScreenPresenter mAddPresenter;

   @Mock
   private AddsService addsService;

   // ...

   @Before
   public void setUp() throws Exception {
      mAddPresenter = new AddScreenPresenter(addsService, 
           mView, mContactDatabaseHelper);
      // ...
   }
}

因此,基本上唯一的區別是,我會將模擬傳遞給服務。

現在,第二個問題是:如何從活動中調用presenter構造函數? 好吧,您不……這就是依賴注入的全部思想。 您應該使用匕首來提供演示者。 我認為這已經是您的工作,而且我想這就是您的活動中的事情:

@Inject
AddScreenPresenter addScreenPresenter;

因此,您需要做的就是在您的模塊中提供一個提供者方法,並提供該方法並能夠將其注入。

您還可以使組件返回模塊提供的presenter:

@Component(...)
public interface AddScreenComponent {
   AddScreenPresenter getPresenter();
}

然后在您的活動中,您將執行以下操作:

addScreenPresenter = component.getPresenter();

我在這里沒有任何偏好。 關鍵是要了解,您不應該自己構建對象(除非在@Module )。 根據經驗,任何時候只要看到new被使用,就意味着您對該對象有嚴格的依賴性,應該提取該對象以進行注入。 因此,這就是為什么您應該避免在活動中創建演示者的原因。 它將演示者耦合到活動。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM