-
-
Notifications
You must be signed in to change notification settings - Fork 134
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
ViewModel unit test problems with SavedStateHandle.navArgs() #210
Comments
Hi 👋 You can receive the initial query in the constructor of the ViewModel, making use of dependency injection principles. Let me know if this helped 🙂 |
I closed this but I’ll be paying attention to your replies here 😃 |
Do you mean I'm not able to use either (argFrom or navArgs)? When is the case I can use them in the ViewModel and also be able to Unit test it?
|
One option would be passing by the compose screen... which looks a bit bad.
|
No, you can and should use one of those options, but do it before calling the ViewModel constructor and pass the result to it. Are you using Hilt or any other DI framework? |
Hilt, yes. |
Ok, so search for assisted injection. This is a good practice either way, it’s not just a workaround to this issue 😁 |
Let me try to find you an example of this |
Coming from Manuel himself ☝️ |
I'll give it a try. Thank you for the fast responses! |
Hmm I actually went through this and gave a quick DM to Manuel, and it seems this is not recommended 🤔 |
So.. you can either use a setter and call it from the Composable, or you can mock the navArgs method.. Are you using a mocking library? |
Yes, Mockito. |
Hmm not sure how to mock these methods with mockito 🤔 Maybe your best bet until they fix the assisted injection in Hilt is to use a setter like you said before. If you were using manual dep injection this would be trivial, so yeah, it’s annoying that this issue is worse because Hilt is missing this support. |
@raamcosta should this issue be reopened? I'm facing the same issue and seems related with Does NOT work @HiltViewModel
class CountryLocalIdConfirmationViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val _viewState = MutableStateFlow<ViewState>(savedStateHandle.navArgs()) // <======= Unit tests fail here
} Does work @HiltViewModel
class CountryLocalIdConfirmationViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val _viewState = MutableStateFlow(
ViewState(
countryLocalIdType = savedStateHandle.getOrThrow("countryLocalIdType"),
countryLocalId = savedStateHandle.getOrThrow("countryLocalId"),
checkBoxValue = savedStateHandle.getOrThrow("checkBoxValue"),
)
)
} This is the current generated code override fun argsFrom(savedStateHandle: SavedStateHandle): ViewState {
return ViewState(
countryLocalIdType = countryLocalIdTypeEnumNavType.get(savedStateHandle, "countryLocalIdType") ?: throw RuntimeException("'countryLocalIdType' argument is mandatory, but was not present!"),
countryLocalId = DestinationsStringNavType.get(savedStateHandle, "countryLocalId") ?: throw RuntimeException("'countryLocalId' argument is mandatory, but was not present!"), // <======= Unit tests fail here
checkBoxValue = DestinationsBooleanNavType.get(savedStateHandle, "checkBoxValue") ?: throw RuntimeException("'checkBoxValue' argument is not mandatory and not nullable but was not present!"),
)
} maybe should generate something like this? override fun argsFrom(savedStateHandle: SavedStateHandle): ViewState {
return ViewState(
countryLocalIdType = savedStateHandle["countryLocalIdType"] ?: throw RuntimeException("'countryLocalIdType' argument is mandatory, but was not present!"),
countryLocalId = savedStateHandle["countryLocalId"] ?: throw RuntimeException("'countryLocalId' argument is mandatory, but was not present!"),
checkBoxValue = savedStateHandle["checkBoxValue"] ?: throw RuntimeException("'checkBoxValue' argument is not mandatory and not nullable but was not present!"),
)
} or maybe making
seems to work fine, also |
I just realised that import android.net.Uri
....
internal val DECODED_EMPTY_STRING: String = Uri.decode(ENCODED_EMPTY_STRING)
...
private val DECODED_DEFAULT_VALUE_STRING_PREFIX: String = Uri.decode(ENCODED_DEFAULT_VALUE_STRING_PREFIX) that might be the reason we are not able to access it in the unit tests. |
That is the reason, yes. I can make it a lazy initialized field, and if the tests don't need it (it seems like that is your case) then that would work. I'll reopen this to see if I can come up with a better solution. Thanks @epool |
Until then, use assited injection (if your framework allows it, as said above, Hilt as issues with it atm) and pass the arguments to the ViewModel (this is much better from a clean code perspective in my opinion). If not, you can set the args from the outside with some setter. |
This should be fixed guys @epool @luanbarbosa-sanoma please test version 1.x.20 and let me know! |
Hi,
I'm using
SavedStateHandle.navArgs()
to get the navigation arguments on my ViewModel. However, on my Unit tests the call fails withNoClassDefFoundError: Could not initialize class
error. I've added the value directly in mySavedStateHandle
with no success.How can I manage to test the ViewModel with the navigation arguments without having to do a UI test?
Code snippets:
The text was updated successfully, but these errors were encountered: