[英]Using Dagger with Espresso
我計划在我的應用程序多模塊上創建 Espresso 測試,我即將創建第一個 Espresso 測試,但我看到的是在我的應用程序上我沒有可以偽造它的AppComponent
。 因為我想在我的功能模塊上添加測試,所以我將從現在開始在那里創建TestApp
、 TestRunner
。
我的功能模塊上有一個FeatureComponent
,它是通過ComponentFactory
從App
注入的,所以我想像這樣創建一個 class :
@Component (
dependencies = [ MoreComponents::class],
modules = [ DataSourceModule::class ]
)
interface FeatureOneComponent {
fun activityOneSubComponent(): FeatureOneActivity.Component.Factory
fun activityTwoSubComponent(): FeatureTwoActivity.Component.Factory
@Component.Factory
interface Factory {
fun create(
dependencies
):FeatureOneComponent
}
}
interface FeatureOneProvider {
fun getFeatureOneComponent(): FeatureOneComponent
}
///ACTIVITY
class FeatureOneActivity : AppCompatActivity() {
//this comes from Subcomponent is what I want to MOCK
@Inject lateinit var presenter
//these comes from the factory and I have it mocked
@Inject lateinit var manager
override fun onCreate(){
(applicationContext as FeatureOneProvider).getFeatureOneComponent().activityOneSubComponent().create(this).inject(this)
}
}
@Subcomponent(modules = [ActivityOneModule::class]) <--- THIS I WANT TO MOCK
interface Component {
fun inject(activity: FeatureOneActivity)
@SubComponent.Factory
interface Factory {
fun create(@BindsInstance activity: FeatureOneActivity): Component
}
}
@Module
interface ActivityOneModule {
@Binds
fun bindPresenter(impl: PresenterImpl): Contract.Presenter
}
測試
class MyTestApp : Application(), FeatureOneProvider {
override fun getFeatureOneComponent(): FeatureOneComponent {
return DaggerMockFeatureOneComponent.create()
}
}
@Component(
modules = [MockFeatureOneModules::class]
)
interface MockFeatureOneComponent : FeatureOneComponent {
//I NEED TO MOCK THE SUBCOMPONENT WITH `MockSubcomponent`
}
@Component
object MockFeatureOneModules {
@Provides
fun providesManager() : MyManager = mock(MyManager)
}
//I want to use this module to replace the subcomponent of my activity
@Module
object MockSubcomponent() {
@Provides
fun providesFakePresenter() : FeatureOneContract.Presenter = mock { FeatureOneContract.Presenter::class.java }
}
當我運行我的測試並放置一個調試器點時,我看到除了演示者之外的所有東西都被模擬了,那是因為演示者在
@Subcomponent(modules = [ActivityOneModule::class]
interface Component {
fun inject(activity: FeatureOneActivity)
@SubComponent.Factory
interface Factory {
fun create(@BindsInstance activity: FeatureOneActivity): Component
}
}
@Module
interface ActivityOneModule {
@Binds
fun bindPresenter(impl: PresenterImpl): Contract.Presenter
}
在我的測試組件中,我無權“覆蓋”這個子組件,所以一切都被模擬了,但是這個子組件我需要這個模擬。
我不知道這是否是最好的主意,但如果我沒有誤解你,你希望這個 Presenter 返回一個mock {}
。 你可以做的改變是:
interface
以abstract class
@Component(
modules = [MockFeatureOneModules::class]
)
abstract class MockFeatureOneComponent : FeatureOneComponent {
abstract fun subcomponent() : MockComponent.FactoryMock
override fun activityOneSubComponent(): FeatureOneActivity.Component.Factory {
return subcomponent()
}
@Subcomponent
interface MockComponent : FeatureOneActivity.Component {
@Subcomponent.Factory
interface FactoryMock : FeatureOneActivity.Component.Factory {
override fun create....
}
}
}
就是這樣,它應該工作。
據我所知,您有多個模塊、組件和子組件,但是由於它們的大多數名稱在您發布的代碼中並不完全匹配,也不是您發布的錯誤日志,我不得不猜測哪里出了問題.
相反,這樣的事情怎么樣。
public interface SomeComponent {
WhateverClass1 provideWhatever1();
WhateverClass2 provideWhatever2();
WhateverRepository1 provideWhateverRepository1();
SomeOtherComponent getSomeOtherComponent();
// and so on and on
}
然后讓您的生產組件看起來像這樣:
@SomeComponentSingleton
@Component(modules = { ... },
dependencies = { ... })
public interface SomeProductionScopedComponent extends SomeComponent {
@Component.Builder
interface Builder {
// you know best what needs to go here
SomeProductionScopedComponent build();
}
}
和這個
@SomeComponentSingleton
@Component(dependencies = SomeComponent.class, modules =
{ ... })
public interface TestSomeComponent {
@Component.Builder
interface Builder {
Builder bindCoreComponent(SomeComponent coreComponent);
@BindsInstance
Builder bindContext(Context context);
TestSomeComponent build();
}
}
然后,假設您在某種程度上使用這些構建器手動實例化組件,只要它們依賴於接口( SomeComponent
),您應該能夠將 ProductionSomeComponent 或 TestSomeComponent 綁定到您的模塊中。
有道理還是給出了一些提示?
您的示例代碼很難理解和實際問題。 但是我知道你想為你的功能模塊設置 expresso 測試,你需要為它設置 dagger 組件。
因此,我可以為您提供一些指南和示例代碼,以便您可以非常簡單地為您的 espresso 測試遵循和設置您的匕首架構。
首先,您需要為 espresso 測試設置/創建應用程序,如下所示:
class MyTestApplication : MyApplication() {
//Call this from MyApplication onCreate()
override fun initDaggerGraph() {
component = DaggerTestAppComponent.builder()
.application(this)
.appLifecycle(appLifecycle)
.build()
component.inject(this)
}
}
然后像這樣創建您的測試應用程序組件:
//Add all of your dependent modules in this TestAppModule
@Component(modules = [TestAppModule::class])
interface TestAppComponent : AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: Application): Builder
@BindsInstance
fun appLifecycle(appLifecycle: AppLifecycle): Builder
fun build(): TestAppComponent
}
fun inject(activityTest: SomeActivityTest) //Your activity where to inject
}
此外,請確保在啟動活動時在您的測試活動 class 中初始化您的組件,如下所示:
val component = MyApplication.instance.component as TestAppComponent
component.inject(this)
現在您已經完成了所有設置,您的依賴項應該可以解決,並且您的 espresso 測試應該可以工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.