首页 > 解决方案 > 你如何嘲笑平等?

问题描述

假设我有一个界面

interface IFoo{
    val foo:String
}

我想创建与它们的foo字符串匹配的 IFF 相等的类。

简单的例子:

class A(override val foo:String):IFoo{
    val somethingIrrelevant = "bar"

    override fun equals(other: Any?): Boolean {
        return if(other is IFoo) foo == other.foo else false
    }

    override fun hashCode(): Int {
        return Objects.hash(foo)
    }
}

看起来相对简单,但是这个测试用例:

@Test
fun mockingEquality(){
    //given
    val a = A("alpha")
    val b = A("alpha")

    assertThat(a,`is`(b)) //succeeds


    //when
    val c = mock(A::class.java)
    whenever(c.foo).thenReturn("alpha")

    //then
    assertThat(c, `is`(a)) //fails
}

失败了

Expected: is <A@589b17d>
     but: was <Mock for A, hashCode: 263885523>

这是为什么?以及如何正确模拟A课程以使该测试成功?

标签: unit-testingjunitkotlinmockitohamcrest

解决方案


这里的问题是,当您创建模拟时,该对象没有任何行为,除非您明确模拟它。这包括你的equalshashCode方法。

在您的示例中,一个“修复”是模拟equalsandhashCode方法,但显然这不会为您的测试增加任何价值。简单地说,您可以反转您的断言 ( assertThat(a, is(c))),这恰好可以工作,因为最终结果将是a.equals(c), 并且a是类的真实实例A而不是模拟,并且具有.foo模拟属性。

我怀疑您的示例过于简化,但在那些给定的情况下,您应该更喜欢只创建一个真实实例而不是模拟(例如val c = A("alpha"),而不是mock(A::class.java))。

这里的一些其他方法可能是:

如果您可以获得该类的真实实例,另一种方法是使用间谍。例如:

val c = spy(A("other value"))
doReturn("mock value").whenever(c).foo 

但是您可以在文档中看到,这些部分模拟类的方法不是推荐的方法。


推荐阅读