假设我有一个界面
interface IFoo{
val foo:String
}
我想创建等于IFF的
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
方法,但是显然,这不会给您的测试增加任何值(value)。琐碎地,您可以反转恰好起作用的断言(assertThat(a, is(c))
),因为最终结果将是a.equals(c)
,并且a
是A
类的真实实例,而不是模拟类,并且具有.foo
属性 mock 。
我怀疑您的示例过于简化了,但是在这些给定的情况下,您应该更喜欢创建一个真实的实例而不是模拟(例如val c = A("alpha")
而不是mock(A::class.java)
)。
这里的一些其他方法可能是:
如果您可以获得类的真实实例,则另一种方法是使用 spy 。例如:
val c = spy(A("other value"))
doReturn("mock value").whenever(c).foo
但是您可以在documentation中看到,不建议使用这些部分模拟类的方法。
关于unit-testing - 您如何 mock 平等?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54542172/