5

Already referred this very similar issue.

I am trying to write my first coroutine test.

Getting this error,

Exception in thread "Test worker @coroutine#1"

java.lang.NullPointerException at <app_package_name>.data.source.usecase.GetSourcesCountUseCase.invoke(GetSourcesCountUseCase.kt:10)

Unit Test code

class AddTransactionScreenViewModelImplTest {
    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()

    private val dataStore: MyDataStore = mock()
    private val getCategoriesUseCase: GetCategoriesUseCase = mock()
    private val getSourcesUseCase: GetSourcesUseCase = mock()
    private val getTitleSuggestionsUseCase: GetTitleSuggestionsUseCase = mock()
    private val navigationManager: NavigationManager = mock()
    private val dispatcherProvider: DispatcherProvider = TestDispatcherProviderImpl(
        testDispatcher = mainDispatcherRule.testDispatcher,
    )
    private val getSourcesCountUseCase: GetSourcesCountUseCase = mock()
    private val insertTransactionUseCase: InsertTransactionUseCase = mock()
    private val updateSourcesUseCase: UpdateSourcesUseCase = mock()

    private lateinit var addTransactionScreenViewModel: AddTransactionScreenViewModel

    @Before
    fun setUp() {
        addTransactionScreenViewModel = AddTransactionScreenViewModelImpl(
            dataStore = dataStore,
            getCategoriesUseCase = getCategoriesUseCase,
            getSourcesUseCase = getSourcesUseCase,
            getTitleSuggestionsUseCase = getTitleSuggestionsUseCase,
            navigationManager = navigationManager,
            dispatcherProvider = dispatcherProvider,
            getSourcesCountUseCase = getSourcesCountUseCase,
            insertTransactionUseCase = insertTransactionUseCase,
            updateSourcesUseCase = updateSourcesUseCase,
        )
    }

    @After
    fun tearDown() {
    }

    @Test
    fun getTransactionTypesForNewTransaction(): Unit = runTest {
        whenever(
            getSourcesCountUseCase.invoke()
        ).thenReturn(1)
        whenever(
            getSourcesUseCase.invoke()
        ).thenReturn(
            flow {
                emptyList<Source>()
            },
        )
        whenever(
            getCategoriesUseCase.invoke()
        ).thenReturn(
            flow {
                emptyList<Category>()
            },
        )

        val result: List<TransactionType> = addTransactionScreenViewModel
            .transactionTypesForNewTransaction.first()
        Assert.assertEquals(
            arrayOf(
                TransactionType.INCOME,
                TransactionType.EXPENSE,
                TransactionType.TRANSFER
            ),
            result,
        )
    }
}

Code I am testing

override val transactionTypesForNewTransaction: StateFlow<List<TransactionType>> = flow {
        val sourceCount = getSourcesCountUseCase()
        val transactionTypesForNewTransaction = TransactionType.values().filter {
            if (sourceCount > 1) {
                it != TransactionType.ADJUSTMENT
            } else {
                it != TransactionType.ADJUSTMENT && it != TransactionType.TRANSFER
            }
        }
        emit(
            value = transactionTypesForNewTransaction,
        )
    }.defaultListStateIn()

MainDispatcherRule (Source)

class MainDispatcherRule(
    val testDispatcher: TestDispatcher = UnconfinedTestDispatcher(),
) : TestWatcher() {
    override fun starting(description: Description) {
        Dispatchers.setMain(testDispatcher)
    }

    override fun finished(description: Description) {
        Dispatchers.resetMain()
    }
}

TestDispatcherProviderImpl

class TestDispatcherProviderImpl(
    testDispatcher: TestDispatcher,
) : DispatcherProvider {
    override val main: CoroutineDispatcher = testDispatcher
    override val io: CoroutineDispatcher = testDispatcher
    override val default: CoroutineDispatcher = testDispatcher
    override val unconfined: CoroutineDispatcher = testDispatcher
}

DispatcherProvider

interface DispatcherProvider {
    val main: CoroutineDispatcher
    val io: CoroutineDispatcher
    val default: CoroutineDispatcher
    val unconfined: CoroutineDispatcher
}
1
  • Please add a comment if anything else is required. Commented May 5, 2022 at 2:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.