': Parameter specified as non-null is null: method com.craftboxx.toolbar.HeaderData.<init>, parameter syncStatus

When I run unit tests for my AssignmentViewmodelTest.kt I get the following exception:

Parameter specified as non-null is null: method com.craftboxx.toolbar.HeaderData.<init>, parameter syncStatus
java.lang.NullPointerException: Parameter specified as non-null is null: method com.craftboxx.toolbar.HeaderData.<init>, parameter syncStatus
    at com.craftboxx.toolbar.HeaderData.<init>(HeaderData.kt)
    at com.craftboxx.base.BaseViewModel.<init>(BaseViewModel.kt:30)
    at com.craftboxx.screens.main.assignments.AssignmentsViewModel.<init>(AssignmentsViewModel.kt:60)
    at com.craftboxx.viewmodels.AssignmentsViewModelTest.setup(AssignmentsViewModelTest.kt:37)
    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 ... the rest deleted

com.craftboxx.viewmodels.AssignmentsViewModelTest > test_user_firstName FAILED
    java.lang.NullPointerException at AssignmentsViewModelTest.kt:37

1 test completed, 1 failed
> Task :app:testDevDebugUnitTest FAILED
FAILURE: Build failed with an exception.

AssignmentsViewModelTest.kt:

      @ExperimentalCoroutinesApi
    class AssignmentsViewModelTest{
        
        private  val vm = mock<AssignmentsViewModel>()
    
        private val sessionRepo = mock<SessionRepository>()
        private val assignmentsRepo = mock<AssignmentsRepository>()
        private val userRepository = mock<UserRepository>()
        private val res = mock<ResourceResolver>()
        private val prefs =  mock<Prefs>()
        private val onlineManager = mock<OnlineManager>()
    
    
    
    
    
    
        @Before
        fun setup() {
           val vm = AssignmentsViewModel(res, prefs, onlineManager, assignmentsRepo, userRepository, sessionRepo)
        }
    
    
        @OptIn(ExperimentalCoroutinesApi::class)
        @Test
        fun test_user_firstName()= runTest{
            val headerData = Mockito.mock(UserRepository::class.java)
            val userRepository = mock<UserRepository>()
            Mockito.`when`(userRepository.getUser()).thenReturn(headerData.getUser())
            val user = headerData.getUser()
            assertEquals(user,headerData)
        }



}

HeaderData.kt

data class HeaderData(
        private val res: ResourceResolver,
        val syncStatus: LiveData<SyncStatus>,
        private val lastSyncTime: LiveData<Long>,
        private val onClickAction: () -> Unit
) {
    val isVisible = Transformations.map(syncStatus) {
        it?.let { status ->
            when (status) {
                is SyncStatus.Done -> false
                else -> true
            }
        }
    }

    val isIconVisible = Transformations.map(syncStatus) {
        it?.let { status ->
            when (status) {
                is SyncStatus.Downloading, is SyncStatus.Uploading -> true
                else -> false
            }
        }
    }

    val isUploading = Transformations.map(syncStatus) {
        it?.let { status ->
            when (status) {
                is SyncStatus.Uploading -> true
                else -> false
            }
        }
    }

    val statusText = Transformations.map(syncStatus) {
        it?.let { status ->
            when (status) {
                is SyncStatus.Downloading, is SyncStatus.Uploading -> R.string.syncBarSynchronizingTitle
                else -> R.string.syncBarOfflineTitle
            }
        }
    }

    val description = Transformations.map(syncStatus) {
        it?.let { status ->
            when (status) {
                is SyncStatus.Offline -> lastSyncTime.value?.let { time ->
                    if (time == 0L) return@let null
                    DateUtils.formatDuration(res, time)
                }
                is SyncStatus.Uploading -> if (status.count > 1) {
                    res.str(R.string.syncBarRemainingTitle, status.count)
                } else {
                    res.str(R.string.syncBarOneRemainingTitle)
                }
                else -> null
            }
        }
    }

    fun onClick() {
        when (syncStatus.value) {
            is SyncStatus.Offline, is SyncStatus.Uploading -> onClickAction()
            else -> return
        }
    }
}

AssignmentViewModel.kt:

class AssignmentsViewModel(
    private val res: ResourceResolver,
    prefs: Prefs,
    onlineManager: OnlineManager,
    private val assignmentsRepository: AssignmentsRepository,
    private val userRepository: UserRepository,
    private val sessionRepository: SessionRepository
) : BaseViewModel(res, prefs, onlineManager), AssignmentItem.Listener, AssignmentHeaderItem.Listener, AlertDialogFragment.Listener{}

Why are the tests failing and what do I need to do in order for them to pass?

below my UserRepository.kt where I have implemented UserRepository.kt logic

i

import androidx.lifecycle.LiveData
import com.craftboxx.api.responses.UserResponse
import com.craftboxx.data.Result
import com.craftboxx.database.entities.User
import com.craftboxx.utils.CoroutineContextProviders
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File

open class UserRepository(
        private val userLocalDataSource: UserLocalDataSource,
        private val userRemoteDataSource: UserRemoteDataSource,
        private val coroutineContext: CoroutineContextProviders
) {

    open suspend fun getUser(): Result<UserResponse> = withContext(coroutineContext.IO) {
        val result = userRemoteDataSource.getUser()
        result.data?.let {
            val user = it.user.toLocal()
            userLocalDataSource.saveUser(user)
        }
        result
    }

    open suspend fun updateUserTimeZone() = withContext(coroutineContext.IO) {
        userRemoteDataSource.updateUserTimeZone()
    }

    open suspend fun getLocalUser(): User? {
        return userLocalDataSource.getLocalUser()
    }

    open fun getLocalUserLiveData(): LiveData<User?> {
        return userLocalDataSource.getLocalUserLiveData()
    }

    open suspend fun updateUserPicture(fileUrl: String) = withContext(coroutineContext.IO) {
        val result = userRemoteDataSource.updateUserPicture(createImagePart(fileUrl))
        result.data?.let {
            val user = it.user.toLocal()
            userLocalDataSource.saveUser(user)
        }
        result
    }

    open suspend fun deleteUserPicture() = withContext(coroutineContext.IO) {
        val result = userRemoteDataSource.deleteUserPicture()
        if (result.status == Result.Status.SUCCESS) {
            userLocalDataSource.getLocalUser()?.let {
                userLocalDataSource.deletePicture(it.id)
            }
        }
        result
    }

    private fun createImagePart(fileUrl: String): MultipartBody.Part {
        val imageFile = File(fileUrl)
        val ext = imageFile.extension
        val name = "profile_picture"

        val imageFileNameEx = if (ext.isEmpty()) "${name}.jpg" else "${name}.$ext"
        val mediaType = if (ext.isEmpty()) "image/jpg" else "image/$ext"

        val imageBody = imageFile.asRequestBody(mediaType.toMediaTypeOrNull())
        return MultipartBody.Part.createFormData("upload_file", imageFileNameEx, imageBody)
    }
}


Solution 1:[1]

First, your test has nothing to do with the code from AssignmentViewModel. You don't use it inside the test. Anyway, the reason your test is failing, is that you call a function of a mocked object userRepository.getUser() But your mocked object(userRepository) doesn't know what to do there, hence the null pointer exception.

You can fix your test with something like:

val headerData = HeaderData(…
Mockito.`when`(userRepository.getUser()).thenReturn(headerData)

In general you have to make sure that your mocked objects have an "answer" to the functions you are calling of them. That's what the above line does, it makes that a call to the mocked userRepository.getUser() returns the headerData that is created and doesn't result in a null pointer exception.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Stephan