Unit testing 你怎么嘲笑平等?

Unit testing 你怎么嘲笑平等?,unit-testing,junit,kotlin,mockito,hamcrest,Unit Testing,Junit,Kotlin,Mockito,Hamcrest,假设我有一个接口 interface IFoo{ val foo:String } 我想创建当它们的foo字符串匹配时相等的类 简单的例子: class A(override val foo:String):IFoo{ val somethingIrrelevant = "bar" override fun equals(other: Any?): Boolean { return if(other is IFoo) foo == other.foo

假设我有一个接口

interface IFoo{
    val foo:String
}
我想创建当它们的
foo
字符串匹配时相等的类

简单的例子:

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
类以使该测试成功?

这里的问题是,当您创建模拟时,该对象没有行为,除非您显式模拟它。这包括
equals
hashCode
方法

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

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

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

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

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

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

有没有一种方法可以告诉模拟程序像往常一样只使用模拟值运行方法
equals
hashCode
?比如“返回除这些方法之外的默认值”?(是的,这是我能将问题分解为的最简单的方法。)编辑了答案,给出了更多选项,2使用
存根final/private/equals()/hashCode()方法失败。那些方法*不能*被存根/验证。
Ah good catch,没有意识到有那个限制。更新以删除该建议。