android - 如何在使用 Espresso 的仪器测试中注入 Mocked Presenter of Activity
问题描述
我已经尝试了一个星期。我已经抓取了所有可用的文章,但它们的实现或示例不足或停留在 Espresso 测试的步骤中。
我的 Android 应用程序遵循 MVP 架构(并且在 Java 中)
场景:[仅举一个例子]我有HomeActivity
一个HomePresenter
使用 Dagger2 的。(HomeModule
通过. void inject(HomeActivity activity)
_HomeComponent
在我的 espressoTest 中,HomeActivity
我想注入一个模拟礼物。我没有AppModule
通过AppComponent
. 网络上的大多数例子都是这样做的(所以他们只是创建一个新的 testApplication 然后做需要的)
我不想使用 productFlavours 注入或提供模拟类的方式,因为它不能让我控制这些Mockito.when
方法。
所以基本上。我想注入一个模拟演示者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);
家活动
HomeComponent component = DaggerHomeComponent.builder()
.appComponent(((App) getApplication()).getComponent())
.homeModule(new HomeModule(this))
.build();
再次。在我的测试(浓缩咖啡)中,我想注入一个由 Mockito 设置的 mockedHomePresenter。所以我可以对我的观点进行单元测试。
解决方案
解决问题的关键是要有这样一个Dagger 模块,它在的仪器测试中提供一个模拟PresenterHomeActivity
而不是“真实”的。
为此,需要执行以下 2 个额外操作(您可能还想查看示例)。
- 将HomeActivity的Component的实例化委托给某个抽象。
- 用插装测试代替抽象的实现来提供模拟。
我将在下面的示例中使用Kotlin。
定义委托接口:
interface HomeComponentBuilder {
fun build(view: IHomeContract.View): HomeComponent
}
将HomeComponent
初始化从HomeActivity
委托实现移动:
class HomeComponentBuilderImpl constructor(private val app: App) : HomeComponentBuilder {
override fun build(view: IHomeContract.View): HomeComponent =
DaggerHomeComponent.builder()
.homeModule(HomeModule(view))
.build()
}
使委托处于应用程序“范围”中,以便您可以交换其实现以进行检测测试:
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)
TestHomeComponent
对于扩展的检测测试创建HomeComponent
:
@HomeScope
@Component(modules = [TestHomeModule::class])
interface TestHomeComponent : HomeComponent
whereTestHomeModule
提供了一个模拟Presenter
@Module
class TestHomeModule {
@Provides
fun providePresenter(): IHomeContract.Presenter = mock()
}
剩下要做的就是做一个测试委托实现
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()
}
...
}
其余的都是标准的。创建一个AndroidJUnitRunner
使用的自定义TestAppImpl
:
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()
}
}
推荐阅读
- django-rest-framework - 不使用 partial = true 在序列化程序上引发异常
- sql - 根据日期连接表
- angular - Angular 8电子无法读取未定义的“一次”属性
- wireshark - 从不同的操作系统和浏览器生成 pcap 文件
- android - 即使在 android studio 中开启了 USB 调试,模拟器也未在连接的 USB 设备中列出
- symfony - 从工作人员发送电子邮件时,除非引发异常,否则不会发送
- mysql - 从具有不同信息的 3 个表中获取数据
- reactjs - React 功能组件状态变化不会触发子组件重新读取其 props
- php - 根据PHP更改所有页面上的链接
- swift - AppStore 查看崩溃日志