android - 如何在 Kotlin Android 中对异常进行单元测试
问题描述
我正在尝试编写一个单元测试来测试是否抛出异常,但我不完全确定如何做到这一点。
这是代码:
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())
}
}
}
我怎样才能做到这一点?我需要为函数提供一些东西,以便它会抛出异常,但我不知道这是如何工作的。
谢谢!
解决方案
请避免嘲笑您尝试测试的课程,因为您想看到“真实”的行为。
我的第一步是稍微改变你的类并将字段移动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 进行断言
推荐阅读
- python - tfp.keras.layers:如果数据格式是 'channels_first' ,我可以将网络输入形状指定为 'channels_last' 吗?
- javascript - Axios Post,但不记录数据
- visual-studio - Xamarin 表单不会部署 Visual Studio 2019
- html - CSS为缓存创建问题?
- sql-server - 如何在 Docker for Mac 上运行的 SQL Server 上启用 SQL Server Browser 服务?
- python - 将函数的“try/except”错误检查扩展/重新应用到其子函数?
- mysql - 仅当系统变量存在时,如何设置它?
- firebase - 调用 Firebase.initializeApp() ,但我的代码中已经有了它
- angular - 错误 HttpErrorResponse {headers: HttpHeaders, status: 400, statusText: "OK", url: "https://reqres.in/api/register", ok: false, …}
- python - 在虚拟环境中遇到熊猫安装错误