': 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 |
