mockito / mockito-kotlin

Using Mockito with Kotlin
MIT License
3.11k stars 201 forks source link

any() is throwing an exception #291

Closed GianfrancoMS closed 5 years ago

GianfrancoMS commented 5 years ago

This is the test I'm trying to run

package com.gianfranco.stormy.features.current.data

import com.gianfranco.stormy.common.connection.NetworkVerifier
import com.gianfranco.stormy.common.functional.Failure
import com.gianfranco.stormy.features.WeatherConstants.Companion.NOW
import com.gianfranco.stormy.features.WeatherDatabaseFactory
import com.gianfranco.stormy.features.WeatherServiceFactory
import com.gianfranco.stormy.features.current.data.database.CurrentWeatherDao
import com.gianfranco.stormy.features.current.data.network.WeatherWebService
import com.gianfranco.stormy.features.daily.data.database.DailyForecastDao
import com.gianfranco.stormy.features.hourly.data.database.HourlyForecastDao
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.whenever
import kotlinx.coroutines.experimental.runBlocking
import org.amshove.kluent.shouldBeTrue
import org.junit.Test

class CurrentWeatherDataRepositoryTest {
    private val weatherWebService = mock<WeatherWebService> {
        on { getWeather(any(), any()) } doReturn (WeatherServiceFactory.makeWeatherWrapper(NOW))
    }
    private val currentWeatherDao = mock<CurrentWeatherDao> {
        on { getCurrentWeather() } doReturn (listOf(WeatherDatabaseFactory.makeCurrentWeather(NOW)))
    }
    private val hourlyForecastDao = mock<HourlyForecastDao>()
    private val dailyForecastDao = mock<DailyForecastDao>()
    private val networkVerifier = mock<NetworkVerifier>()
    private val currentWeatherRepository = CurrentWeatherRepositoryImpl(
        weatherWebService,
        currentWeatherDao,
        hourlyForecastDao,
        dailyForecastDao,
        networkVerifier
    )

    @Test
    fun `Data is fetched from network and persisted in the database`() {
        whenever(networkVerifier.isConnected()).thenReturn(true)

        val result = runBlocking {
            currentWeatherRepository.getCurrentWeather(any(), any(), shouldRefresh = true)
        }

        result.either({ left ->
            when (left) {
                is Failure.GeneralError -> System.out.println(left.message)
                is Failure.ServerError -> System.out.println(left.message)
                is Failure.NetworkConnection -> System.out.println(left.message)
                else -> System.out.println("WTF")
            }
        }, {})

        result.isRight.shouldBeTrue()
    }
}

But it throws the following exception:

Invalid use of argument matchers!
0 matchers expected, 2 recorded:
-> at com.gianfranco.stormy.features.current.data.CurrentWeatherDataRepositoryTest$Data is fetched from network and persisted in the database$result$1.doResume(CurrentWeatherDataRepositoryTest.kt:58)
-> at com.gianfranco.stormy.features.current.data.CurrentWeatherDataRepositoryTest$Data is fetched from network and persisted in the database$result$1.doResume(CurrentWeatherDataRepositoryTest.kt:60)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

And then, JUnit's Assertion Error:

java.lang.AssertionError: Expected value to be true, but was false
at kotlin.test.junit.JUnitAsserter.fail(JUnitSupport.kt:56)
    at kotlin.test.Asserter$DefaultImpls.assertTrue(Assertions.kt:147)
    at kotlin.test.junit.JUnitAsserter.assertTrue(JUnitSupport.kt:30)
    at kotlin.test.Asserter$DefaultImpls.assertTrue(Assertions.kt:157)
    at kotlin.test.junit.JUnitAsserter.assertTrue(JUnitSupport.kt:30)
    at kotlin.test.AssertionsKt__AssertionsKt.assertTrue(Assertions.kt:34)
    at kotlin.test.AssertionsKt.assertTrue(Unknown Source)
    at org.amshove.kluent.internal.AssertionsKt.assertTrue(Assertions.kt:7)
    at org.amshove.kluent.BasicKt.shouldBeTrue(Basic.kt:18)
    at com.gianfranco.stormy.features.current.data.CurrentWeatherDataRepositoryTest.Data is fetched from network and persisted in the database(CurrentWeatherDataRepositoryTest.kt:55)

If I replace any() with other value like Double.MAX_VALUE, the test alway pass.

bohsen commented 5 years ago

The exception tells you the problem. You are combining raw values with matchers (any() creates a Matcher):

currentWeatherRepository.getCurrentWeather(<matcher>, <matcher>, <raw value>)

Mockito enforces that you should only use either matchers xor raw values.

Btw. Not đź’Ż percent sure of best practice, but I usually avoid using matchers in the methods I'm testing.

nhaarman commented 5 years ago

Seems resolved, thanks @bohsen!