Cannot create Test component as subclass of Main component when contributed subcomponents are present
See original GitHub issueSo I have my main app component:
@MergeComponent(AppScope::class)
@AppScope
interface AppComponent {
@Component.Factory
interface Factory {
fun create(@BindsInstance application: Application): AppComponent
}
}
And a subclass in my androidTest folder:
@MergeComponent(AppScope::class)
@AppScope
interface TestAppComponent: AppComponent {
@Component.Factory
interface Factory {
fun create(
@BindsInstance application: Application,
@BindsInstance mockInterceptor: MockInterceptor
): TestAppComponent
}
}
This works relatively well, except when i introduce a contributed subcomponent:
@ContributesSubcomponent(
parentScope = AppScope::class,
scope = PodOnboardingScope::class
)
@PodOnboardingScope
interface PodOnboardingComponent {
fun activityComponentFactory(): PodOnboardingActivityComponent.Factory
@ContributesSubcomponent.Factory
interface Factory {
fun create(): PodOnboardingComponent
}
@ContributesTo(AppScope::class)
interface FactoryCreator {
fun podOnboardingComponentFactory(): Factory
}
}
This leads to this error:
TestAppComponent.java:9: error: conflicting entry point declarations:
public abstract interface TestAppComponent extends com.xfinity.dh.pods.app.di.AppComponent, com.xfinity.dh.pods.di.PodOnboardingComponent.FactoryCreator, com.xfinity.dh.pods.app.di.AppInjectors, anvil.component.com.xfinity.dh.app.di.testappcomponent.PodOnboardingComponentA.ParentComponent {
^
@org.jetbrains.annotations.NotNull @Override anvil.component.com.xfinity.dh.app.di.testappcomponent.PodOnboardingComponentA.SubcomponentFactory anvil.component.com.xfinity.dh.app.di.testappcomponent.PodOnboardingComponentA.ParentComponent.podOnboardingComponentFactory()
@org.jetbrains.annotations.NotNull anvil.component.com.xfinity.dh.pods.app.di.appcomponent.PodOnboardingComponentA.SubcomponentFactory anvil.component.com.xfinity.dh.pods.app.di.appcomponent.PodOnboardingComponentA.ParentComponent.podOnboardingComponentFactory()
I have a temporary workaround which is to move my injectors/accessors to their own interfaces in the main app, and look those up in my component registry by their interfaces. Once i do that, i can remove the inheritance, and i generally don’t ever refer to the AppComponent directly unless i’m actually creating it. It works, but it seems odd to have to do this.
Issue Analytics
- State:
- Created a year ago
- Comments:5
Top Results From Across the Web
ContributesSubcomponent issue in testing #459 - GitHub
When creating integration tests with real dagger component, I had created TestAppComponent, TestUserComponent, in each app, with excluded modules which ...
Read more >How do you override a module/dependency in a unit test with ...
We've to set the test component in App class before the MainActivity is created - because StringHolder is injected in the onCreate callback....
Read more >Testing with Dagger
One of the benefits of using dependency injection frameworks like Dagger is that it makes testing your code easier. This document explores some...
Read more >Testing Components – Testing Angular
The TestBed creates and configures an Angular environment so you can test particular application parts like Components and Services safely ...
Read more >Component testing scenarios - Angular
The purpose of the spec is to test the component, not the service, and real services can be trouble.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

Yeah, that’s what i’ve done is to move the injectors to a different interface. However, traditional testing in dagger usually extends the main component to produce the app component, and it works. That’s the only reason I bring this up as an issue is that it’s something i see done a lot in non anvil based dagger.
To help others here, the solution suggested by @vRallev is good. The key here is that you can still have some form of inheritance if you need it. For example if you swap out an injected Component by a test component.
So if you previously have a component like this:
And a test component like this:
You can now extract out an interface:
And for the production and the test component you extend from that interface: