【问题标题】:How do you mock equality?你如何嘲笑平等?
【发布时间】:2019-02-05 20:02:55
【问题描述】:

假设我有一个界面

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-testing junit kotlin mockito hamcrest


    【解决方案1】:

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

    对于您的示例,一个“修复”是模拟 equalshashCode 方法,但显然这不会为您的测试增加任何价值。简单地说,您可以反转您的断言 (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 
    

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

    【讨论】:

    • 有没有办法告诉模拟运行方法equalshashCode 像往常一样只使用模拟值?像“返回除了这些方法的默认值”吗? (是的,这是我可以将问题分解为最简单的方法。)
    • 编辑了答案以提供更多选项
    • 2 失败,you stub either of: final/private/equals()/hashCode() methods. Those methods *cannot* be stubbed/verified.
    • 啊,很好,没有意识到有这个限制。已更新以删除该建议。
    猜你喜欢
    • 2011-04-10
    • 1970-01-01
    • 2014-10-27
    • 2016-10-02
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    相关资源
    最近更新 更多