问题描述
我已经尝试了一个星期.我已经抓取了所有可用的文章,但它们的实现或示例不足或停留在 Espresso 测试的步骤上.
I have been trying this for a week. And I have crawled every article available but their implementations or examples fall short or stop at the steps of Espresso Tests.
我的 Android 应用程序遵循 MVP 架构(并且使用 Java)
My Android Application follows MVP architecture (And is in Java)
场景:[仅举一个例子]我有一个 HomeActivity
,它使用 Dagger2 获取一个 HomePresenter
.(提供通过 HomeComponent
中的 void inject(HomeActivity activity)
暴露的 HomeModule
中的方法.
Scenario: [Giving just one example]I have a HomeActivity
which gets a HomePresenter
using Dagger2. (Provides method in the HomeModule
exposed through a void inject(HomeActivity activity)
in the HomeComponent
.
在我的 HomeActivity
espressoTest 中,我想注入一个模拟礼物.我没有通过 AppComponent
在 AppModule
中公开这个依赖项.网络上的大多数示例都做了哪些(所以他们只是创建一个新的 testApplication 然后做需要的)
In my espressoTest for HomeActivity
I would like to inject a mockpresent.I Have not exposed this dependencies inside an AppModule
through an AppComponent
. which most examples on the net do (So they just create a new testApplication and then do the needfull)
我不想使用 productFlavours 注入或提供模拟类的方式,因为它不能让我控制 Mockito.when
方法.
I do not want to use the productFlavours way of injecting or providing mockclasses as it doesnt give me control over the Mockito.when
methods.
所以基本上.我想注入一个模拟演示器,为了我在 espresso 中的单元测试,我可以在其中执行任何 Mockito.when()
.
So basically. I would like to inject a mockpresenter wherein i can do whatever Mockito.when()
s on it for the sake of my unit tests in espresso.
HomeComponent
@HomeScope
@Component(modules = HomeModule.class,dependencies = AppComponent.class)
public interface HomeComponent {
void inject(HomeActivity activity);
}
家庭模块
@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);
}
}
应用组件
@Component(modules = {AppModule.class,RepositoryModule.class})
@AppScope
public interface AppComponent {
void inject(App app);
FlowsRepository flowRepository();
LoanRepository loanRepository();
UserRepository userRepository();
}
应用模块
@Module
public class AppModule {
private Context appContext;
public AppModule(@NonNull Context context) {
this.appContext = context;
}
@Provides
@AppScope
public Context context() {
return appContext;
}
}
应用
component = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
component.inject(this);
家庭活动
HomeComponent component = DaggerHomeComponent.builder()
.appComponent(((App) getApplication()).getComponent())
.homeModule(new HomeModule(this))
.build();
再来一次.在我的测试(浓缩咖啡)中,我想注入 Mockito 设置的模拟 HomePresenter.所以我可以对我的视图进行单元测试.
Once again. In my tests (espresso) i would like to inject a mockedHomePresenter the set by Mockito. So I can just unit test my views.
推荐答案
解决问题的关键是要有这样一个Dagger Module,它提供了一个模拟Presenter在 HomeActivity
的插桩测试中,而不是真实的"测试.
The key point in resolving the problem is to have such a Dagger Module that provides a mock Presenter in HomeActivity
's instrumented test instead of the "real" one.
为此,需要执行以下 2 个额外操作(您可能还想查看 示例).
For this the following 2 extra actions need to be done (you might also want to see an example).
- 将 HomeActivity 的 Component 的实例化委托给某种抽象.
- 替换检测测试中抽象的实现以提供模拟.
- Delegate instantiation of HomeActivity's Component to some abstraction.
- Substitute the implementation of the abstraction in instrumented tests to provide mocks.
我将在下面的示例中使用 Kotlin.
I'll use Kotlin in the example below.
定义委托接口:
interface HomeComponentBuilder {
fun build(view: IHomeContract.View): HomeComponent
}
将 HomeComponent
初始化从 HomeActivity
移动到委托实现:
Move the HomeComponent
initialisation from HomeActivity
to the delegate implementation:
class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerHomeComponent.builder()
.homeModule(HomeModule(view))
.build()
}
使委托位于应用程序范围"中,以便您可以交换其实现以进行检测:
Make the delegate be in application "scope" so that you could interchange its implementation for instrumented tests:
interface App {
val homeComponentBuilder: HomeComponentBuilder
...
}
App
实现现在应该包含
class AppImpl : Application(), App {
override val homeComponentBuilder: HomeComponentBuilder by lazy {
HomeComponentBuilderImpl(this@AppImpl)
}
...
}
HomeActivity
中的组件初始化如下所示:
Component initialisation in HomeActivity
looks as follows:
(application as App)
.homeComponentBuilder
.build(this)
.inject(this)
对于插装测试,创建扩展 HomeComponent
的 TestHomeComponent
:
For instrumented testing create TestHomeComponent
that extends HomeComponent
:
@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent
其中 TestHomeModule
提供了一个模拟 Presenter
where TestHomeModule
provides a mock Presenter
@Module
class TestHomeModule {
@Provides
fun providePresenter(): IHomeContract.Presenter = mock()
}
剩下要做的是实现测试委托
What's left to do is to make a test delegate implementation
class TestHomeComponentBuilderImpl : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerTestHomeComponent.builder()
.testTestHomeModule(TestHomeModule())
.build()
}
并在TestAppImpl
class TestAppImpl : Application(), App {
override val homeComponentBuilder: HomeComponentBuilder by lazy {
TestHomeComponentBuilderImpl()
}
...
}
其他都是标准的.创建一个使用 TestAppImpl
的自定义 AndroidJUnitRunner
:
The rest is standard. Create a custom AndroidJUnitRunner
that uses TestAppImpl
:
class TestAppRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context)
}
并将其添加到 app
模块 build.gradle
and add it to app
module build.gradle
defaultConfig {
testInstrumentationRunner "your.package.TestAppRunner"
...
}
使用示例:
@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()
}
}
这篇关于如何在 Espresso 的仪器测试中注入模拟活动演示者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!