Closed ampeixoto closed 9 months ago
Hi @ampeixoto,
The simplest solution is to just make the module public
. If users need to replace the module for testing then it seems reasonable to consider the module part of the public API.
Another (usually more difficult) option is to split foo
library into 2 separate Gradle libraries, e.g.
foo
- API onlyfoo-impl
- implementation and Hilt modulesThen have your libraries depend on just the API, :foo
, and the tests can then @BindValue
whatever they want since the Hilt modules are not included. Your Gradle application would need to depend on foo-impl
so that the implementation is provided when generating the components for your app.
However, for most cases the simple option of just making your module public should be good enough.
Hi @bcorso!
Sorry for the (looong) delay, but I completely forgot about this. However, I recently faced the problem again and remembered I opened this ticket.
The problem with the simpler solution you propose, that that I really don't want to the module to expose the implementation... And the second solution is a bit too cumbersome IMO.
Thanks for the suggestions anyway.
Meanwhile I search a bit and found a pretty good suggestion on SO that works! Here it is: https://stackoverflow.com/a/76182220/1204249
Hopefully it will help other people as well.
If you're going that route it may be simpler to just use @DisableInstallInCheck
on your internal module, e.g.
@Module(includes = [InternalDomainModule::class])
@InstallIn(SingletonComponent::class)
class DomainModule
@Module
@DisableInstallInCheck // This annotation allows us to avoid installing this module directly.
internal class InternalDomainModule {
@Provides
@Singleton
fun provideDatabase() : Database = DatabaseImpl()
@Provides
@Singleton
fun provideLoginService(database: Database) : LoginService = LoginServiceImpl(database)
}
However, if you're just worried about the visibility of the provides methods, couldn't you just make the methods themselves internal
, e.g. ?
@Module
@InstallIn(SingletonComponent::class)
class DomainModule {
@Provides
@Singleton
internal fun provideDatabase() : Database = DatabaseImpl()
@Provides
@Singleton
internal fun provideLoginService(database: Database) : LoginService = LoginServiceImpl(database)
}
@bcorso Thanks for the suggestions!
I didn't know about the first one, but the second one is exactly what I want, and works perfectly!
How can I not have thought about that solution??
We can close this :)
Hello,
I would like to know if it is possible to replace a binding from a hilt module, while this hilt module is in another gradle module and has the
internal
modifier?Basically, imagine the following situation:
In module
:my-lib
I have 3 classes:In the module
:app
I'm able to injectMyService
wherever I want in the production code.However, when I try to replace in some test class in
:app
:Of course I get a compilation error saying
is bound multiple times
. One due to theMyServiceModule
and another one due to the@BindValue
in the test.And I am not able to use
@UninstallModules
and@TestInstallIn
annotations since theMyService
hilt module is internal.So Is there any workaround (or proper way to do it) that I am not aware of?
(BTW, this is very similar to this stackoverflow issue)