Android 用匕首配浓咖啡
我计划在我的应用程序多模块上创建浓缩咖啡测试,我将创建第一个浓缩咖啡测试,但我看到的是,在我的应用程序上,我没有可以伪造的Android 用匕首配浓咖啡,android,kotlin,android-espresso,dagger-2,dagger,Android,Kotlin,Android Espresso,Dagger 2,Dagger,我计划在我的应用程序多模块上创建浓缩咖啡测试,我将创建第一个浓缩咖啡测试,但我看到的是,在我的应用程序上,我没有可以伪造的AppComponent。因为我想在我的功能模块上添加测试,所以我将从现在开始在那里创建TestApp,TestRunner 我的功能模块上有一个FeatureComponent,它是通过ComponentFactory从App注入的,所以我想创建这样一个类: @Component ( dependencies = [ MoreComponents::class],
AppComponent
。因为我想在我的功能模块上添加测试,所以我将从现在开始在那里创建TestApp
,TestRunner
我的功能模块上有一个FeatureComponent
,它是通过ComponentFactory
从App
注入的,所以我想创建这样一个类:
@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
}
为了更好地理解这个问题
当我运行我的测试并设置一个调试器点时,我看到除了演示者之外,所有的东西都被模拟了,这是因为演示者处于
@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
}
在我的测试组件中,我没有“覆盖”这个子组件的权限,所以一切都是模拟的,但这个子组件和我需要这个模拟。据我所知,您有多个模块、组件和子组件,但由于它们的大多数名称在您发布的代码中都不匹配,您也没有发布错误日志,我得猜猜哪里出了问题 相反,像这样的事情怎么样
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();
}
}
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
}
val component = MyApplication.instance.component as TestAppComponent
component.inject(this)
还有这个
@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组件 所以,我可以给你一些指导方针和示例代码,这样你就可以很简单地按照你的dagger架构为你的浓缩咖啡测试做准备 首先,您需要按照以下方式设置/创建用于浓咖啡测试的应用程序:
@SomeComponentSingleton
@Component(modules = { ... },
dependencies = { ... })
public interface SomeProductionScopedComponent extends SomeComponent {
@Component.Builder
interface Builder {
// you know best what needs to go here
SomeProductionScopedComponent build();
}
}
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
}
val component = MyApplication.instance.component as TestAppComponent
component.inject(this)
然后创建测试应用程序组件,如下所示:
@SomeComponentSingleton
@Component(modules = { ... },
dependencies = { ... })
public interface SomeProductionScopedComponent extends SomeComponent {
@Component.Builder
interface Builder {
// you know best what needs to go here
SomeProductionScopedComponent build();
}
}
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
}
val component = MyApplication.instance.component as TestAppComponent
component.inject(this)
此外,在启动活动时,请确保在测试活动类中初始化组件,如下所示:
@SomeComponentSingleton
@Component(modules = { ... },
dependencies = { ... })
public interface SomeProductionScopedComponent extends SomeComponent {
@Component.Builder
interface Builder {
// you know best what needs to go here
SomeProductionScopedComponent build();
}
}
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
}
val component = MyApplication.instance.component as TestAppComponent
component.inject(this)
现在您已经完成了所有的设置,您的依赖关系应该得到解决,您的浓缩咖啡测试也应该能够正常工作。我不知道这是否是最好的主意,但如果我没有误解您的意思,您希望此演示者返回一个
模拟{}
。您可以做的更改包括:
接口
更改为抽象类
就这样,它应该可以工作。您不能覆盖组件。您需要在测试中使用“测试组件”,在生产代码中使用“真实组件”。然而,从你发布的代码来看,很难说你在匕首设置中哪里出了问题。是的,但是如果我的子组件有一个
modules=[…]
如何伪造这些?让我用clear编辑我的问题code@Shark编辑我的问题,问题是如何“覆盖”我的生产子组件上的模块,并使用我的模拟子组件上的模拟模块。Well,您的生产子组件不使用硬编码模块列表吗?让我试着发布一些东西,看看你是否捕捉到了理想。你是否将FeatureOneComponent
绑定到ApplicationComponent?你确定它绑定的是TestF1Component而不是ProductionF1Component吗?@StuartDTO基本上,TestComponent将包含模块,这些模块将提供(某些)生产对等组件的模拟或测试变体,这只是显示了你应该走的大致方向。这不是一个分步指南或问题的解决方案,只是演示了如何绕过当前存在的问题-绑定生产模块而不是组件中的测试模块。让我用匹配的代码更新问题。您能重新检查问题吗?我编辑了它,它编译了,它工作了,但是我缺少了模拟子组件模块的部分…这是另一种方式,我不想在我的测试中注入,我正在尝试创建一个TestSubcomponent,检查我的问题@subcomponent(modules=[ActivityOneModule::class]
我想模拟这个模块,但我不能模拟这个子组件,其他东西都被模拟了。