Как выполнить модульное тестирование исключений Mulit-Catch-исключений Kotlin Android - PullRequest
0 голосов
/ 01 октября 2019

Я пытаюсь написать модульный тест, который проверяет, было ли выброшено исключение, но я не совсем уверен, как это сделать.

Вот код:

class GpsInfo {

    private lateinit var locationManager : LocationManager

    fun getGpsInfo(activity: Activity) : Location? {
        locationManager = activity.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        var gpsCoordinates: Location
        try {
            gpsCoordinates = getGpsCoordinatesFromGpsProvider(locationManager)
        } catch(e: UnableAccessGPSProvider) {
            gpsCoordinates = getGpsCoordinatesFromNetwork(locationManager)
        } catch(e: Exception) {
            throw UnableGetGpsCoordinates("Cant get GPS coordinates")
        }

        return gpsCoordinates
    }

    private fun getGpsCoordinatesFromGpsProvider(locationManager: LocationManager) : Location {
        val gpsCoordinates = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
        if (gpsCoordinates == null) {
            throw UnableAccessGPSProvider("Cant get GPS coordinates from GPS Provider")
        }
        return gpsCoordinates
    }

    private fun getGpsCoordinatesFromNetwork(locationManager: LocationManager) : Location {
        val gpsCoordinates = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
        if (gpsCoordinates == null) {
            throw UnableAccessNetwork("Cant get GPS coordinates from network")
        }
        return gpsCoordinates
    }

И вот моя грустная попытка юнит-тестирования, я пытаюсь достичь этого с помощью шутливого класса:

import android.app.Activity
import io.mockk.every
import io.mockk.mockk
import org.junit.*
import kotlin.test.assertFailsWith

class GpsServiceUnitTest {
    private val gps = mockk<GpsInfo>()

    @Before
    fun iniz() {
        every { gps.getGpsInfo(Activity()) } throws UnableAccessGPSProvider("No GPS found")
    }

    @Test
    fun testFails() {
        assertFailsWith(UnableAccessGPSProvider::class) {
            gps.getGpsInfo(Activity())
        }
    }
}

Как мне этого добиться? Мне нужно что-то передать функции, чтобы она выдала исключение, но я не понимаю, как это будет работать.

Спасибо!

1 Ответ

0 голосов
/ 01 октября 2019

Пожалуйста, избегайте насмешек над классом, который вы пытаетесь протестировать, поскольку вы хотите увидеть «реальное» поведение.

Моим первым шагом было бы немного изменить ваш класс и переместить поле locationManager в конструктор. :

class GpsInfo(private val locationManager : LocationManager) {

    fun getGpsInfo(): Location? {
        var gpsCoordinates: Location
        try {
            gpsCoordinates = getGpsCoordinatesFromGpsProvider(locationManager)
        } catch (e: UnableAccessGPSProvider) {
            gpsCoordinates = getGpsCoordinatesFromNetwork(locationManager)
        } catch (e: Exception) {
            throw UnableGetGpsCoordinates("Cant get GPS coordinates")
        }

        return gpsCoordinates
    }

    private fun getGpsCoordinatesFromGpsProvider(locationManager: LocationManager): Location {
        val gpsCoordinates = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
        if (gpsCoordinates == null) {
            throw UnableAccessGPSProvider("Cant get GPS coordinates from GPS Provider")
        }
        return gpsCoordinates
    }

    private fun getGpsCoordinatesFromNetwork(locationManager: LocationManager): Location {
        val gpsCoordinates = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)
        if (gpsCoordinates == null) {
            throw UnableAccessNetwork("Cant get GPS coordinates from network")
        }
        return gpsCoordinates
    }
}

Теперь вы можете легко смоделировать поле, чтобы оно вызывало исключение:

import com.nhaarman.mockito_kotlin.doThrow
import com.nhaarman.mockito_kotlin.mock
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.catchThrowable

@Test
fun `should throw UnableGetGpsCoordinates exception`() {
    val locationManagerMock : LocationManager = mock {
        on { getLastKnownLocation(any()) } doThrow UnableAccessGPSProvider()
    }

    val throwable = catchThrowable { GpsInfo(locationManagerMock).getGpsInfo() }

    assertThat(throwable).isNotNull()
}

Вы также можете оставить locationManager в качестве параметра метода и смоделировать его для теста,но тогда потребовалось бы больше усилий, чтобы протестировать его, потому что нам пришлось бы издеваться два раза - активность и вызов .getSystemService(Context.LOCATION_SERVICE).

Кстати: я рекомендую использовать библиотеку nhaarman для насмешки и assertJ для утверждения

...