Unit Testing Fragments that use lateinit ViewModel












0















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?










share|improve this question



























    0















    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?










    share|improve this question

























      0












      0








      0








      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?










      share|improve this question














      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?







      android unit-testing kotlin viewmodel






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 14 '18 at 19:46









      BlondeSwanBlondeSwan

      1148




      1148
























          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
          });


          }
          });














          draft saved

          draft discarded


















          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
















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          List item for chat from Array inside array React Native

          Thiostrepton

          Caerphilly