Android Retrofit2,Dagger2单位测试



我学习如何测试Android中MVP体系结构的演示者层,我的演示者使用Raturofit 2,在我的活动中,我使用dagger2作为对我的演示者的依赖性注入,这是我的dagger和dagger和主持人注入看起来像:

@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;
}

我已经写了单元测试类并模拟了改造类,但是当我运行时,出现错误:

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;
}
}

我知道改造课是最后一类,现在我坚持下去,不知道如何在测试类中创建演示者对象。请帮助我,如何在构造函数中使用Raterrofit创建演示者类的对象。随时询问我的问题是否还不够清楚,并非常感谢您的帮助。

我个人会让主持人不依赖Retrofit类,而是对Retrofit创建的服务 - 这些都是模拟的。

很难从您发布的代码中说出您的演示者实际使用的服务,但是为了简单起见,可以说它仅使用一个服务,也可以说是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是如何依赖改造的?由于您的演示者取决于它,因此应该已经提供了这一点。您不需要为此更改任何东西。dagger能够弄清楚如何向方法providesAddsService提供Retrofit

请注意,我假设您可以在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);
      // ...
   }
}

基本上唯一的区别是我将模拟传递给服务。

现在是第二个问题:如何从活动中调用主持人构造函数?好吧,你没有...这是依赖注入的整个想法。您应该使用dagger为主持人提供。我认为这已经是您所做的,我想这就是您的活动中的意思:

@Inject
AddScreenPresenter addScreenPresenter;

因此,您需要做的就是在模块中使用提供者的方法,并能够注入它。

您还可以使组件返回模块提供的演示者:

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

然后在您的活动中,您会做类似的事情:

addScreenPresenter = component.getPresenter();

我在这里真的没有任何偏好。关键是要了解您不应自己构建对象(除非在@Module s内部)。每当您看到使用new时,经过经验,这意味着您对该对象有严格的依赖性,并且应该提取它要被注入。因此,这就是为什么您应该避免在活动中创建主持人的原因。它将将演示者与活动相结合。

相关内容

  • 没有找到相关文章

最新更新