Unit Testing Fragments that use lateinit ViewModel
I am attempting to write some unit tests for an Android Project, but am struggling to find a solution that fits the architecture that is set in place.
Just for reference, here is an example of the Architecture set in place for Logging in:
LoginFragment
class LoginFragment : Fragment(), Injectable {
/**
* VARIABLES
*/
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var loginViewModel: LoginViewModel
var binding by autoCleared<LoginFragmentBinding>()
var dataBindingComponent: DataBindingComponent = FragmentDataBindingComponent(this)
// Fragment life cycle and other methods
}
LoginViewModel
class LoginViewModel
@Inject constructor(val authRepository: AuthRepository) : ViewModel() {
fun login(username: String, password: String): LiveData<LoginResponse> {
authRepository.login(username, password)
}
LoginRepository
@Singleton
class AuthRepository @Inject constructor(
val projectService: ProjectService,
val sessionData: SharedPrefs
) {
fun login(username: String, password: String): LiveData<LoginResponse> {
// Login logic
}
}
Project Service
interface ProjectService {
@POST("user/login")
fun postLogin(@Body body: LoginBody): LiveData<ApiResponseWrapper<LoginRemote>>
}
With that, I believe I need to initialize an instance of the LoginFragment in order to access the ViewModel and make to login call. I think this is necessary because the fragment binds everything to work together (not sure, it's not my set up and I'm new to Android Development).
Is there a better way to get access to the ViewModel's login function in order to run Unit Tests on it's calls with the architecture that is set in place?
Moving on, as an example, here is an example of how I am attempting to test logging a user in:
LoginViewModelTests
@Test
fun login() {
//
val result = runBlocking {
loginCoroutine()
}
Assert.assertTrue(result)
}
suspend fun loginCoroutine(): Boolean {
val loginFragment = LoginFragment()
return suspendCoroutine { continuation ->
loginFragment.loginViewModel
.login(maleUsername, malePassword)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
continuation.resume(true)
},
onValidationError = {
continuation.resume(false)
})
})
}
}
As you can see, I initialize the LoginFragment in order to call the loginViewModel's login method. And then after completion, I can run my tests on the response.
However, when attempting to run, I get the error:
lateinit property loginViewModel has not been initialized
How do I resolve this issue with it being an injectable lateinit variable? Or what is recommended to test this login method over the implementation I am attempting?
add a comment |
I am attempting to write some unit tests for an Android Project, but am struggling to find a solution that fits the architecture that is set in place.
Just for reference, here is an example of the Architecture set in place for Logging in:
LoginFragment
class LoginFragment : Fragment(), Injectable {
/**
* VARIABLES
*/
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var loginViewModel: LoginViewModel
var binding by autoCleared<LoginFragmentBinding>()
var dataBindingComponent: DataBindingComponent = FragmentDataBindingComponent(this)
// Fragment life cycle and other methods
}
LoginViewModel
class LoginViewModel
@Inject constructor(val authRepository: AuthRepository) : ViewModel() {
fun login(username: String, password: String): LiveData<LoginResponse> {
authRepository.login(username, password)
}
LoginRepository
@Singleton
class AuthRepository @Inject constructor(
val projectService: ProjectService,
val sessionData: SharedPrefs
) {
fun login(username: String, password: String): LiveData<LoginResponse> {
// Login logic
}
}
Project Service
interface ProjectService {
@POST("user/login")
fun postLogin(@Body body: LoginBody): LiveData<ApiResponseWrapper<LoginRemote>>
}
With that, I believe I need to initialize an instance of the LoginFragment in order to access the ViewModel and make to login call. I think this is necessary because the fragment binds everything to work together (not sure, it's not my set up and I'm new to Android Development).
Is there a better way to get access to the ViewModel's login function in order to run Unit Tests on it's calls with the architecture that is set in place?
Moving on, as an example, here is an example of how I am attempting to test logging a user in:
LoginViewModelTests
@Test
fun login() {
//
val result = runBlocking {
loginCoroutine()
}
Assert.assertTrue(result)
}
suspend fun loginCoroutine(): Boolean {
val loginFragment = LoginFragment()
return suspendCoroutine { continuation ->
loginFragment.loginViewModel
.login(maleUsername, malePassword)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
continuation.resume(true)
},
onValidationError = {
continuation.resume(false)
})
})
}
}
As you can see, I initialize the LoginFragment in order to call the loginViewModel's login method. And then after completion, I can run my tests on the response.
However, when attempting to run, I get the error:
lateinit property loginViewModel has not been initialized
How do I resolve this issue with it being an injectable lateinit variable? Or what is recommended to test this login method over the implementation I am attempting?
add a comment |
I am attempting to write some unit tests for an Android Project, but am struggling to find a solution that fits the architecture that is set in place.
Just for reference, here is an example of the Architecture set in place for Logging in:
LoginFragment
class LoginFragment : Fragment(), Injectable {
/**
* VARIABLES
*/
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var loginViewModel: LoginViewModel
var binding by autoCleared<LoginFragmentBinding>()
var dataBindingComponent: DataBindingComponent = FragmentDataBindingComponent(this)
// Fragment life cycle and other methods
}
LoginViewModel
class LoginViewModel
@Inject constructor(val authRepository: AuthRepository) : ViewModel() {
fun login(username: String, password: String): LiveData<LoginResponse> {
authRepository.login(username, password)
}
LoginRepository
@Singleton
class AuthRepository @Inject constructor(
val projectService: ProjectService,
val sessionData: SharedPrefs
) {
fun login(username: String, password: String): LiveData<LoginResponse> {
// Login logic
}
}
Project Service
interface ProjectService {
@POST("user/login")
fun postLogin(@Body body: LoginBody): LiveData<ApiResponseWrapper<LoginRemote>>
}
With that, I believe I need to initialize an instance of the LoginFragment in order to access the ViewModel and make to login call. I think this is necessary because the fragment binds everything to work together (not sure, it's not my set up and I'm new to Android Development).
Is there a better way to get access to the ViewModel's login function in order to run Unit Tests on it's calls with the architecture that is set in place?
Moving on, as an example, here is an example of how I am attempting to test logging a user in:
LoginViewModelTests
@Test
fun login() {
//
val result = runBlocking {
loginCoroutine()
}
Assert.assertTrue(result)
}
suspend fun loginCoroutine(): Boolean {
val loginFragment = LoginFragment()
return suspendCoroutine { continuation ->
loginFragment.loginViewModel
.login(maleUsername, malePassword)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
continuation.resume(true)
},
onValidationError = {
continuation.resume(false)
})
})
}
}
As you can see, I initialize the LoginFragment in order to call the loginViewModel's login method. And then after completion, I can run my tests on the response.
However, when attempting to run, I get the error:
lateinit property loginViewModel has not been initialized
How do I resolve this issue with it being an injectable lateinit variable? Or what is recommended to test this login method over the implementation I am attempting?
I am attempting to write some unit tests for an Android Project, but am struggling to find a solution that fits the architecture that is set in place.
Just for reference, here is an example of the Architecture set in place for Logging in:
LoginFragment
class LoginFragment : Fragment(), Injectable {
/**
* VARIABLES
*/
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var loginViewModel: LoginViewModel
var binding by autoCleared<LoginFragmentBinding>()
var dataBindingComponent: DataBindingComponent = FragmentDataBindingComponent(this)
// Fragment life cycle and other methods
}
LoginViewModel
class LoginViewModel
@Inject constructor(val authRepository: AuthRepository) : ViewModel() {
fun login(username: String, password: String): LiveData<LoginResponse> {
authRepository.login(username, password)
}
LoginRepository
@Singleton
class AuthRepository @Inject constructor(
val projectService: ProjectService,
val sessionData: SharedPrefs
) {
fun login(username: String, password: String): LiveData<LoginResponse> {
// Login logic
}
}
Project Service
interface ProjectService {
@POST("user/login")
fun postLogin(@Body body: LoginBody): LiveData<ApiResponseWrapper<LoginRemote>>
}
With that, I believe I need to initialize an instance of the LoginFragment in order to access the ViewModel and make to login call. I think this is necessary because the fragment binds everything to work together (not sure, it's not my set up and I'm new to Android Development).
Is there a better way to get access to the ViewModel's login function in order to run Unit Tests on it's calls with the architecture that is set in place?
Moving on, as an example, here is an example of how I am attempting to test logging a user in:
LoginViewModelTests
@Test
fun login() {
//
val result = runBlocking {
loginCoroutine()
}
Assert.assertTrue(result)
}
suspend fun loginCoroutine(): Boolean {
val loginFragment = LoginFragment()
return suspendCoroutine { continuation ->
loginFragment.loginViewModel
.login(maleUsername, malePassword)
.observe(loginFragment, Observer {
loginFragment.activity?.onResult(it?.result,
onSuccess = {
continuation.resume(true)
},
onValidationError = {
continuation.resume(false)
})
})
}
}
As you can see, I initialize the LoginFragment in order to call the loginViewModel's login method. And then after completion, I can run my tests on the response.
However, when attempting to run, I get the error:
lateinit property loginViewModel has not been initialized
How do I resolve this issue with it being an injectable lateinit variable? Or what is recommended to test this login method over the implementation I am attempting?
asked Nov 14 '18 at 19:46
BlondeSwanBlondeSwan
1148
1148
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307735%2funit-testing-fragments-that-use-lateinit-viewmodel%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53307735%2funit-testing-fragments-that-use-lateinit-viewmodel%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown