MockK 简单使用

什么是 Mock(模拟)?

模拟是一种创建“假的”对象或系统的过程,用来模仿真实对象的行为。这样,开发者可以在不依赖外部系统的情况下,单独测试自己的代码逻辑。模拟可以让测试更快,因为不需要连接真实的数据库或网络接口等。

模拟的优点

  • 代码隔离:保证测试不受外部依赖影响,测试更稳定可靠。

  • 减少复杂度:避免复杂的测试环境搭建。

  • 行为可控:可以精确地定义模拟对象在各种情况下的表现。

MockK 简介

MockK 是专门为 Kotlin 设计的强大灵活的模拟库,支持 Kotlin 特有的功能(如协程、扩展函数),提供简洁易用的接口,社区活跃,维护良好。

如何添加 MockK 依赖(Gradle)

testImplementation "io.mockk:mockk:1.13.4"

(你可以去官网查看最新版本)

MockK 示例:模拟服务器请求

假设你有一个 WeatherService 类负责从外部API获取天气数据,你可以用 MockK 模拟 API 客户端接口 ApiClient,从而只测试 WeatherService 自己的逻辑。

// 数据类,代表天气信息
data class Weather(val condition: String, val temperature: Int)

// API 客户端接口
interface ApiClient {
    fun fetchWeather(city: String): Weather
}

// 天气服务类,依赖 ApiClient
class WeatherService(private val apiClient: ApiClient) {
    fun getWeather(city: String): Weather {
        return apiClient.fetchWeather(city)
    }
}

// 测试类,使用 MockK 模拟 ApiClient
class WeatherServiceTest {

    private val mockApiClient = mockk<ApiClient>() // 创建 ApiClient 的模拟对象
    private val weatherService = WeatherService(mockApiClient) // 把模拟对象注入 WeatherService

    @Test
    fun `test getWeather returns correct weather data`() {
        val city = "New York"
        val expectedWeather = Weather("Sunny", 25)

        every { mockApiClient.fetchWeather(city) } returns expectedWeather // 设置模拟行为
        
        val actualWeather = weatherService.getWeather(city)
        
        assertEquals(expectedWeather, actualWeather) // 断言结果符合预期
        
        verify { mockApiClient.fetchWeather(city) } // 验证方法被调用过
    }
}

参数匹配器(Argument Matchers)

MockK 可以灵活匹配方法调用的参数:

  • eq(等于):匹配特定值
every { myMock.myMethod(eq("foo")) } returns 42
  • any(任何值):匹配任意参数
every { myMock.myMethod(any()) } returns 42
  • isNull(空值):匹配 null 参数
every { myMock.myMethod(isNull<String>()) } returns 42
  • range(范围):匹配某个范围内的数值
every { myMock.myMethod(range(10, 20)) } returns 42
  • match(自定义条件):匹配符合自定义条件的参数,比如集合
every { myMock.myMethod(match { it.contains("foo") }) } returns 42
  • 抛异常:模拟方法抛出异常
every { myMock.myMethod(any()) } throws RuntimeException("错误")
  • 返回 Unit(无返回值)
justRun { myMock.myMethod(any()) }

Spy(间谍)

Spy 是对真实对象的包装,可以调用真实方法,也可以验证或覆盖部分方法行为。

val realService = WeatherService()
val spyService = spyk(realService)
val weather = spyService.fetchWeather("New York")
verify { spyService.fetchWeather("New York") }
assertEquals("Sunny in New York", weather)

注解用法

MockK 支持用注解简化模拟对象创建:

  • @MockK:创建模拟对象

  • @InjectMockKs:自动将模拟对象注入到测试的主对象里

  • @Spyk:创建部分真实对象的 Spy

示例:

@ExtendWith(MockKExtension::class)
class WeatherServiceTest {

    @MockK
    private lateinit var mockApiClient: ApiClient

    @InjectMockKs
    private lateinit var weatherService: WeatherService

    @Test
    fun testGetWeather() {
        // ...
    }
}

对象模拟(Object Mocking)

Kotlin 的对象(单例)也可以用 mockkObject 来模拟:

object WeatherService {
    fun fetchWeather(city: String) = "Sunny in $city"
}

@Test
fun testMockObject() {
    mockkObject(WeatherService)
    every { WeatherService.fetchWeather("New York") } returns "Cloudy"
    val weather = WeatherService.fetchWeather("New York")
    verify { WeatherService.fetchWeather("New York") }
    assertEquals("Cloudy", weather)
    unmockkObject(WeatherService) // 结束后恢复
}

关键字和含义总结

关键字含义
mockk()创建一个模拟对象(Mock)
every { }定义模拟对象方法的行为
returns模拟方法返回指定值
verify { }验证方法是否被调用过
spyk()创建一个 Spy,包裹真实对象,可以调用真实方法
justRun { }用于模拟返回 Unit(无返回值)的方法
mockkObject模拟 Kotlin 中的单例对象
unmockkObject解除对单例对象的模拟,避免影响其他测试
@MockK注解,创建模拟对象
@InjectMockKs注解,将 Mock 对象自动注入到被测对象
@Spyk注解,创建 Spy 对象
eq()参数匹配器,匹配精确值
any()参数匹配器,匹配任意值
isNull()参数匹配器,匹配 null 参数
range()参数匹配器,匹配一个范围内的数值
match()参数匹配器,根据自定义条件匹配参数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值