Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hilt gives me "Called inject() multiple times" exception #111

Closed
renetik opened this issue Feb 10, 2023 · 11 comments · Fixed by #112
Closed

Hilt gives me "Called inject() multiple times" exception #111

renetik opened this issue Feb 10, 2023 · 11 comments · Fixed by #112

Comments

@renetik
Copy link

renetik commented Feb 10, 2023

Somehow I am not able to inject use to multiple classes that contains cucmber steps with inject of hilt, It works when I use inject is done just in one class containing steps. . How to inject to all classes containg steps whatever i need from hilt ?

@RunWith(AndroidJUnit4::class)
@WithJunitRule(useAsTestClassInDescription = true)
@HiltAndroidTest
class Givens {

    @Rule(order = 0)
    @JvmField
    val hiltRule = HiltAndroidRule(this)

    @Inject
    lateinit var scanner: SensorScanner

    @Before
    fun init() {
        hiltRule.inject()
    }
    .....
and another one similar:
@RunWith(AndroidJUnit4::class)
@WithJunitRule(useAsTestClassInDescription = true)
@HiltAndroidTest
class Whens {

    @JvmField
    val hiltRule = HiltAndroidRule(this)

    @Inject
    lateinit var scanner: SensorScanner

    @Before
    fun init() {
        hiltRule.inject()
    }
......

I tried mutltiple things it still fails in various ways, also could not find any report on SO, almost like if no one use it like this ?

@lsuski
Copy link
Contributor

lsuski commented Feb 10, 2023

I'm not a user of Hilt however AFAIR (when I implemented this) and based on https://github.com/cucumber/cucumber-android#hilt you can use it in 1 class only. You have to inject all dependencies in this class like HiltRuleHolder and then you can inject HiltRuleHolder using cucumber injection to other steps classes and use your dependencies there

@renetik
Copy link
Author

renetik commented Feb 10, 2023

I'm not a user of Hilt however AFAIR (when I implemented this) and based on https://github.com/cucumber/cucumber-android#hilt you can use it in 1 class only. You have to inject all dependencies in this class like HiltRuleHolder and then you can inject HiltRuleHolder using cucumber injection to other steps classes and use your dependencies there

Hi thanks for hint. Just to clarify your solution... It sound like a messy setup to me. Imagine large application with 80% test coverage with 50 files of classes with steps each having various dependency needs. So you say that I will make one class named HiltRuleHolder that will be populated with everything what any test step can need in the execution ? and then I will somehow inject this HiltRuleHolder to all 50 classes containing steps ? I have hard time to imagine this to be right way.

@lsuski
Copy link
Contributor

lsuski commented Feb 10, 2023

I think that the problem is how Hilt works. It can inject to only 1 test class. Usually it is some junit test class so thereiis no problem but in cucumber there are many classes used in test. Maybe something changed since I implemented this but if not then I don't see a way to tell Hilt to inject more than once. Regarding injecting to cucumber classes this is acutally quite easy and clean. In cucumber all glue classes are involved in test. Each class with cucumber annotation is instantiatied if step defined in such class is used in executed scenario. As you can use steps from many classes in 1 scenario there is no way to scope some classes to particular scenario. The same applies to @before methods. Each method with such annotation is executed before each scenario. I suggest to create issue in hilt repository or android issuetracker to allow having many Hilt rules injecting in many classes because this is limitation of Hilt test framework and cucumber only tries to fit it into its world

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Feb 10, 2023

As a dependency injection framework, it might be possible to use Hilt in an ObjectFactory implementation to have it work with Cucumber and inject into multiple classes.

@renetik
Now I haven't used Hilt or Android, so I can't talk about the details with certainty. If you have a need for this and are willing to do the investigation and subsequent implementation you could discuss the possibilities of publishing that implementation as part of Cucumber Android with @lsuski.

@lsuski
Copy link
Contributor

lsuski commented Feb 10, 2023

Hilt mostly relies on annotation processing so I doubt it's possible to use it in ObjectFactory. The only idea I have to workaround Hilt test rule limitation is to scope HiltRuleHolder like classes for particular feature or scenario. This could be done using tags or feature/scenario name or some advanced filtering when Scenario object is passed which is doable IMHO. This would mimick typical junit usage where feature == class and scenario == test method

@mpkorstanje
Copy link
Contributor

Mmh. Cucumber-Spring has much of the same constraints. I solved it there by having 1 special class from which the annotations were read (marked with a specific annotation) and then injecting into the other classes as regular. But t would really depend on how Hilt works and how neatly the Hilt API is separated from the HiltAndroidRule implementation and what else it needs.

@lsuski
Copy link
Contributor

lsuski commented Feb 10, 2023

What you described looks similar to what currently is possible with Hilt and cucumber. By annotation processing I meant that ot is done during compilation by annotation processor, that's why Hilt doesn't need reflection. I thought that Spring processes annotation in the runtime

@lsuski
Copy link
Contributor

lsuski commented Feb 10, 2023

I need to check if there is any option to invoke hilt generated code in ObjectFactory

@renetik
Copy link
Author

renetik commented Feb 13, 2023

Just quick question as i dont see this as good way for us is there some suggestion to use some othe dependency injection library with cucumber-android instead of hilt withou this kind of limitations ?

@lsuski
Copy link
Contributor

lsuski commented Feb 13, 2023

There are many which should work lile Dagger or Koin but if you like Hilt then IMHO having 1 class with all test dependencies is not such big issue. It's similar to having 1 dagger module or component or 1 Koin module where all deps are listed and created. You can also try Hilt EntryPoints api, maybe it will solve this issue as you can declare many entry point classes. However as I'm not a Hilt user I don't know how it works exactly

@lsuski
Copy link
Contributor

lsuski commented Feb 15, 2023

Just to inform you: I'm working on another approach with Hilt to allow injecting in step classes directly instead of HiltRuleHolder

@lsuski lsuski mentioned this issue Feb 16, 2023
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants