[英]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.