如何使用MockK测试依赖Dagger注入的Kotlin类A?
问题描述
我是依赖注入(Dagger)领域的新手,跟着各类教程学习后帮助不大。现有类A、B、C的代码如下:
class C @Inject constructor() { fun doIt(i: Int): Int{ return i*100 } } class B { @Inject constructor() fun doIt(i: Int): Int{ return i*10 } } class A @Inject constructor(val b: B) { // (primary) constructor injection @Inject // field injection lateinit var c: C // late = after init/constructor fun doIt(i: Int): Int{ return c.doIt(i) + b.doIt(i) + 1 } }
尝试用MockK对类A进行单元测试,但没搞懂运作原理,测试代码如下:
internal class ExampleUnitTest2 { @MockK lateinit var c: C @MockK lateinit var b: B @Before fun setUp() = MockKAnnotations.init(this) @Test fun myTest() { coEvery { c.doIt(5) } returns 500 coEvery { b.doIt(5) } returns 50 val a = A(b) assertEquals(a.doIt(5), 555) } }
核心问题
测试代码存在两个关键问题:
- 未初始化类A的
c字段:A中的c是字段注入的lateinit属性,创建A实例时仅传入了构造注入的b,未给c赋值,调用doIt时会抛出UninitializedPropertyAccessException。 - 错误使用
coEvery:coEvery用于Mock挂起函数,而doIt是普通同步函数,应使用every。
解决方法
方案1:手动注入Mock实例
创建A实例后,直接给c字段赋值Mock对象:
internal class ExampleUnitTest2 { @MockK lateinit var c: C @MockK lateinit var b: B @Before fun setUp() = MockKAnnotations.init(this) @Test fun myTest() { // 用every替代coEvery,适配同步函数 every { c.doIt(5) } returns 500 every { b.doIt(5) } returns 50 val a = A(b) // 手动注入c的Mock实例 a.c = c // 预期值为500+50+1=551,原测试用例的555计算错误 assertEquals(a.doIt(5), 551) } }
方案2:用@InjectMockKs自动注入
MockK的@InjectMockKs注解可自动将@MockK标记的实例注入到被测类的构造参数和字段中,无需手动处理:
internal class ExampleUnitTest2 { @MockK lateinit var c: C @MockK lateinit var b: B // 自动注入Mock对象到A实例 @InjectMockKs lateinit var a: A @Before fun setUp() = MockKAnnotations.init(this) @Test fun myTest() { every { c.doIt(5) } returns 500 every { b.doIt(5) } returns 50 assertEquals(a.doIt(5), 551) } }
说明
@InjectMockKs会自动处理两种注入方式:构造注入的参数(如A的b)、字段注入的属性(如A的c),无需手动创建A实例。- 注意修正预期值:原测试用例中的555是计算错误,正确结果应为500+50+1=551。
内容的提问来源于stack exchange,提问作者chtimi59
相关产品推荐
相关产品推荐

