android – How about writing test code for the viewmodel below?

I created a view model to handle authentication (login and register), but I’m having trouble writing unit testing code. Can anyone help me write unit testing code for the view model below?

Authentication View Model:


class AuthenticationViewModel(private val userRepository: UserRepository) : ViewModel() {
    var user = MutableLiveData<Event<UserModel>>()

    var loading = MutableLiveData<Event<Boolean>>()

    var message = MutableLiveData<Event<String>>()

    var error = MutableLiveData<Event<Boolean>>()

    fun userLogin(email: String, password: String): MutableLiveData<Event<UserModel>> {
        loading.value = Event(true)
        val client = userRepository.userLogin(email, password)
        client.enqueue(object : Callback<UserResponse> {
           override fun onResponse(
               call: Call<UserResponse>,
               response: Response<UserResponse>
            ) {
                Log.e("AuthenticationViewModel", "onResponse: " + response.body())
                loading.value = Event(false)
                if (response.isSuccessful) {
                    val responseBody = response.body()?.loginResult
                    error.value = Event(false)
                    userRepository.appExecutors.networkIO.execute {
                        Log.e("AuthenticationViewModel", "userLogin: $responseBody")
                        user.postValue(Event(responseBody!!))
                    }
                } else {
                    Log.e("AuthenticationViewModel", "onResponse fail: ")
                    message.value = Event(response.message())
                    error.value = Event(true)
                }
            }

            override fun onFailure(call: Call<UserResponse>, t: Throwable) {
                Log.e("AuthenticationViewModel", "onFailure: " + t.message)
                loading.value = Event(false)
                message.value = Event(t.message.toString())
                error.value = Event(true)
            }
        })
        return user
    }

    fun userRegister(
        name: String,
        email: String,
        password: String
    ) {
        loading.value = Event(true)
        val client = userRepository.userRegister(name, email, password)
        client.enqueue(object : Callback<UserResponse> {
            override fun onResponse(
                call: Call<UserResponse>,
                response: Response<UserResponse>
            ) {
                Log.e("AuthenticationViewModel", "onResponse: " + response.body())
                loading.value = Event(false)
                if (response.isSuccessful) {
                    error.value = Event(false)
                } else {
                    Log.e("AuthenticationViewModel", "onResponse fail: ")
                    message.value = Event(response.message())
                    error.value = Event(true)
                }
            }

            override fun onFailure(call: Call<UserResponse>, t: Throwable) {
                Log.e("AuthenticationViewModel", "onFailure: " + t.message)
                loading.value = Event(false)
                message.value = Event(t.message.toString())
                error.value = Event(true)
            }
        })
    }

    fun getUserToken() = userRepository.getUserToken()

    fun saveUserToken(token: String?) {
        viewModelScope.launch {
            if (token != null) {
                userRepository.saveUserToken(token)
            }
        }
    }

    fun saveUserName(name: String?) {
        viewModelScope.launch {
            if (name != null) {
                userRepository.saveUserName(name)
            }
        }
    }

    fun saveUserEmail(email: String) {
        viewModelScope.launch {
            userRepository.saveUserEmail(email)
        }
    }

    fun logout() {
        viewModelScope.launch {
            userRepository.clearCache()
        }
    }

}

I’ve tried to write unit testing code, but failed and encountered a NullPointerException

AuthenticationViewModelTest :

@RunWith(MockitoJUnitRunner::class)
class AuthenticationViewModelTest {
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    @Mock
    private lateinit var repository: UserRepository
    private lateinit var viewModel: AuthenticationViewModel
    private val dummyUser = DataDummy.generateDummyUser()

    @Before
    fun setUp() {
        viewModel = AuthenticationViewModel(repository)
    }

    @Test
    fun `when userLogin should return user response when email and password are valid and error is false`() {
        val email = DataDummy.userEmail
        val password = DataDummy.userPassword

        val expectedUser = MutableLiveData<Event<UserModel>>()
        expectedUser.value = Event(dummyUser)

        val expectedError = MutableLiveData<Event<Boolean>>()
        expectedError.value = Event(false)

        `when`(viewModel.userLogin(email, password)).thenReturn(expectedUser)

        val actualUser = viewModel.userLogin(email, password).getOrAwaitValue()
        val actualError = viewModel.error.getOrAwaitValue()

        Mockito.verify(repository).userLogin(email, password)
        assertNotNull(actualUser.peekContent())
        assertFalse(actualError.peekContent())
    }
}

Error Exception

java.lang.NullPointerException
    at com.mankart.mankgram.ui.authentication.AuthenticationViewModel.userLogin(AuthenticationViewModel.kt:32)
    at com.mankart.mankgram.ui.authentication.AuthenticationViewModelTest.when userLogin should return user response when email and password are valid and error is false(AuthenticationViewModelTest.kt:46)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.mockito.internal.runners.DefaultInternalRunner$1$1.evaluate(DefaultInternalRunner.java:55)
    at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:100)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:107)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:41)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)


com.mankart.mankgram.ui.authentication.AuthenticationViewModelTest > when userLogin should return user response when email and password are valid and error is false FAILED
    java.lang.NullPointerException at AuthenticationViewModelTest.kt:46
1 test completed, 1 failed
> Task :app:testDebugUnitTest FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:testDebugUnitTest'.
> There were failing tests. See the report at: file:///C:/Users/asus/AndroidStudioProjects/Submission/Mankgram/app/build/reports/tests/testDebugUnitTest/index.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 2m 29s

Leave a Comment