我已经试了一个星期了。我已经抓取了所有可用的文章,但它们的实现或示例不尽如人意或停留在 Espresso 测试的步骤。
我的 Android 应用程序遵循 MVP 架构(并且是在 Java 中)
场景:[仅举一个例子]
我有一个使用 Dagger2 获取 HomePresenter
的 HomeActivity
。 (在通过 HomeComponent
中的 void inject(HomeActivity activity)
公开的 HomeModule
中提供方法。
在我的 HomeActivity
的 espressoTest 中,我想注入(inject)一个 mockpresent。
我没有通过 AppComponent
在 AppModule
中公开此依赖项。网上的大多数例子都是这样做的(所以他们只是创建一个新的 testApplication 然后做需要的)
我不想使用 productFlavours 方式注入(inject)或提供模拟类,因为它无法让我控制 Mockito.when
方法。
所以基本上。我想注入(inject)一个 mockpresenter,为了在 espresso 中进行单元测试,我可以在其中执行任何 Mockito.when()
操作。
我的代码如下。
主页组件
@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);
主页 Activity
HomeComponent component = DaggerHomeComponent.builder()
.appComponent(((App) getApplication()).getComponent())
.homeModule(new HomeModule(this))
.build();
再来一次。在我的测试(espresso)中,我想注入(inject)一个由 Mockito 设置的 mockedHomePresenter。所以我可以对我的观点进行单元测试。
最佳答案
解决问题的关键点是有这样一个 Dagger 模块,它在 HomeActivity
的插桩测试中提供模拟 Presenter的“真正的”。
为此,需要完成以下 2 个额外操作(您可能还希望看到 example )。
- 将 HomeActivity 的 Component 的实例化委托(delegate)给一些抽象。
- 在插桩测试中替换抽象的实现以提供模拟。
我将在下面的示例中使用 Kotlin。
定义委托(delegate)接口(interface):
interface HomeComponentBuilder {
fun build(view: IHomeContract.View): HomeComponent
}
将 HomeComponent
初始化从 HomeActivity
移至委托(delegate)实现:
class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerHomeComponent.builder()
.homeModule(HomeModule(view))
.build()
}
使委托(delegate)处于应用程序“范围”中,以便您可以为仪器测试交换其实现:
interface App {
val homeComponentBuilder: HomeComponentBuilder
...
}
App
实现现在应该包含
class AppImpl : Application(), App {
override val homeComponentBuilder: HomeComponentBuilder by lazy {
HomeComponentBuilderImpl(this@AppImpl)
}
...
}
HomeActivity
中的组件初始化如下所示:
(application as App)
.homeComponentBuilder
.build(this)
.inject(this)
对于仪器测试,创建扩展 HomeComponent
的 TestHomeComponent
:
@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent
TestHomeModule
提供了一个模拟Presenter
@Module
class TestHomeModule {
@Provides
fun providePresenter(): IHomeContract.Presenter = mock()
}
剩下要做的就是进行测试委托(delegate)实现
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
:
class TestAppRunner : AndroidJUnitRunner() {
override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application = Instrumentation.newApplication(TestAppImpl::class.java, context)
}
并将其添加到app
模块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()
}
}
关于android - 如何使用 Espresso 在 Instrumentation 测试中注入(inject) Mocked Presenter of Activity,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51110120/