如何在ActivityTest中注入Mocked Presenter.即用浓缩咖啡进行仪器测试

yUd*_*Dis 6 tdd android android-espresso dagger-2 android-mvp

我已经尝试了一个星期.我已经抓取了所有可用的文章,但他们的实现或示例不足或停止在Espresso测试的步骤.

我的Android应用程序遵循MVP架构(并且是Java)

场景:[仅举一个例子]我有HomeActivity一个HomePresenter使用Dagger2.(提供方法在HomeModule通过a void inject(HomeActivity activity)中暴露出来HomeComponent.

在我的espressoTest中,HomeActivity我想注入一个模拟演示.我还没有暴露内部的这种依赖性AppModule通过AppComponent.网上的大多数例子都是这样的(所以他们只是创建一个新的testApplication然后做必要的)

我不想使用productFlavours注入或提供模拟类的方式,因为它不能让我控制Mockito.when方法.

所以基本上.我想注入一个mockpresenter,我可以做任何Mockito.when()事情,为了我的浓缩咖啡单位测试.

我的代码如下.

HomeComponent

@HomeScope
@Component(modules = HomeModule.class,dependencies = AppComponent.class)
public interface HomeComponent {
    void inject(HomeActivity activity);
}
Run Code Online (Sandbox Code Playgroud)

HomeModule

@Module
public class HomeModule {

    private final IHomeContract.View view;

    public HomeModule(IHomeContract.View view) {
        this.view = view;
    }

    @Provides
    @HomeScope
    public IHomeContract.Presenter presenter(FlowsRepository flowsRepository, UserRepository userRepository, LoanRepository loanRepository) {
        return new HomePresenter(view, flowsRepository, userRepository, loanRepository);
    }

}
Run Code Online (Sandbox Code Playgroud)

AppComponent

@Component(modules = {AppModule.class,RepositoryModule.class})
@AppScope
public interface AppComponent {
    void inject(App app);

    FlowsRepository flowRepository();
    LoanRepository loanRepository();
    UserRepository userRepository();
}
Run Code Online (Sandbox Code Playgroud)

的AppModule

@Module
public class AppModule {
    private Context appContext;

    public AppModule(@NonNull Context context) {
        this.appContext = context;
    }

    @Provides
    @AppScope
    public Context context() {
        return appContext;
    }
}
Run Code Online (Sandbox Code Playgroud)

应用

component = DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();
        component.inject(this);
Run Code Online (Sandbox Code Playgroud)

HomeActivity

HomeComponent component = DaggerHomeComponent.builder()
                .appComponent(((App) getApplication()).getComponent())
                .homeModule(new HomeModule(this))
                .build();
Run Code Online (Sandbox Code Playgroud)

再来一次.在我的测试中(espresso)我想注入一个模拟的HomePresenter,由Mockito设置.所以我可以单独测试我的观点.

Oni*_*nik 8

解决这个问题的关键是要有这样一个Dagger 模块,它在的仪器测试中提供一个模拟PresenterHomeActivity而不是“真实”的。

为此,需要执行以下 2 个额外操作(您可能还想查看示例)。

  1. 的代表实例HomeActivity组件一些抽象。
  2. 替换仪表测试中抽象的实现以提供模拟。

我将在下面的示例中使用Kotlin

定义委托接口:

interface HomeComponentBuilder {
    fun build(view: IHomeContract.View): HomeComponent
}
Run Code Online (Sandbox Code Playgroud)

HomeComponent初始化从HomeActivity委托实现移到:

class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {

override fun build(view: IHomeContract.View): HomeComponent =
    DaggerHomeComponent.builder()
        .homeModule(HomeModule(view))
        .build()
}
Run Code Online (Sandbox Code Playgroud)

使委托位于应用程序“范围”中,以便您可以将其实现交换为已检测的测试:

interface App {
    val homeComponentBuilder: HomeComponentBuilder
    ...
}
Run Code Online (Sandbox Code Playgroud)

App 实现现在应该包含

class AppImpl : Application(), App {
    override val homeComponentBuilder: HomeComponentBuilder by lazy {
        HomeComponentBuilderImpl(this@AppImpl)
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

组件初始化HomeActivity如下:

(application as App)
        .homeComponentBuilder
        .build(this)
        .inject(this)
Run Code Online (Sandbox Code Playgroud)

对于仪器测试创建TestHomeComponent扩展HomeComponent

@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent
Run Code Online (Sandbox Code Playgroud)

whereTestHomeModule提供了一个模拟Presenter

@Module
class TestHomeModule {

    @Provides
    fun providePresenter(): IHomeContract.Presenter = mock()
}
Run Code Online (Sandbox Code Playgroud)

剩下要做的是进行测试委托实现

class TestHomeComponentBuilderImpl : HomeComponentBuilder {
    override fun build(view: IHomeContract.View): HomeComponent =
        DaggerTestHomeComponent.builder()
             .testTestHomeModule(TestHomeModule())
             .build()
}
Run Code Online (Sandbox Code Playgroud)

并初始化它 TestAppImpl

class TestAppImpl : Application(), App {
    override val homeComponentBuilder: HomeComponentBuilder by lazy {
        TestHomeComponentBuilderImpl()
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

其余为标准。创建一个AndroidJUnitRunner使用的自定义TestAppImpl

class TestAppRunner : AndroidJUnitRunner() {
    override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context)
}
Run Code Online (Sandbox Code Playgroud)

并将其添加到app模块build.gradle

defaultConfig {
    testInstrumentationRunner "your.package.TestAppRunner"
    ...
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

@RunWith(AndroidJUnit4::class)
class HomeActivityTest {
    private lateinit var mockPresenter: IHomeContract.Presenter

    @get:Rule
    val activityRule = ActivityTestRule(HomeActivity::class.java)

    @Before
    fun setUp() {
        mockPresenter = activityRule.activity.presenter
    }

    @Test
    fun activity_onCreate_presenter_should_onViewCreated() {
        verify(mockPresenter).someMethod()
    }
}
Run Code Online (Sandbox Code Playgroud)


C B*_*B J 2

所以。您的问题是您需要创建一个模块来提供用于测试的模拟演示者而不是“真实”的演示者。

这里有一篇很好的文章:Testing with Dagger