@MockK 或 mockk()

@MockK or mockk()

使用 Mockk 进行 Android 单元测试时,声明依赖项时使用的符号有什么不同吗?

class Test {
    private val x: X = mockk()

    private val test = TestClass(x)
...
}

class Test {
    @MockK
    private lateinit var x: X

    @InjectMockKs
    private lateinit var test: TestClass
    
    @Before
    fun setup() {
        MockKAnnotations.init(this)
    }
...
}

来自MockK project

No there is no difference between the two implementations, they are equivalent.

Generally speaking, you can use mockk() when you need to declare mocks dynamically in your code, or if you need, for instance, just a single mock to have its unit functions relaxed (in which case you would build it with mockk(relaxUnitFun = true).

If your mocks have all the same behavior, you can use the annotations version.

如果你的 TestClass 的依赖关系会改变,使用 Annotation 会更好。

因为你只需要再add/delete一个@MockK,不需要关心目标class的构造函数。

原创

@ExtendWith(MockKExtension::class)
class Test {
    @MockK
    private lateinit var x: X

    @InjectMockKs
    private lateinit var test: TestClass
}

TestClass

添加一个依赖项
@ExtendWith(MockKExtension::class)
class Test {
    @MockK
    private lateinit var x: X

    @MockK
    private lateinit var y: Y  // <1> Just add this

    @InjectMockKs
    private lateinit var test: TestClass  // <2> Don't need to add the changed dependency into it's constructor
}

由于以下两个原因,我建议在测试中使用 mockk() 和“简单的”构造函数依赖项注入而不是注释:

  1. mockk() 构建器允许您使用 val 定义不可变变量,这更安全、高效且更好*(就软件开发而言),而使用@Mockk 你应该使用 var 关键字;

  2. @InjectMockKs 并不像看起来那么酷。我在一个项目中遇到了与 Mockito 相同的问题。我的队友删除了构造函数参数中间某处的 class 依赖项之一,构建了 & 运行 代码,但忘记在本地修复 & 运行 测试。他推动了这些更改,但随后我们在“运行 测试”管道阶段出现错误,该错误指向无处,只是 NPE 关于缺少 class。我们花了一些额外的时间终于找到了问题所在,问题是

Mockito will try to inject mocks only either by constructor injection, property injection or setter injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.

https://www.javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/InjectMocks.html