假设我有一个界面
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
类以使测试成功?
答案 0 :(得分:1)
这里的问题是,当您创建模拟时,该对象没有任何行为,除非您明确对其进行模拟。这包括您的equals
和hashCode
方法。
在您的示例中,一个“解决方案”将是模拟equals
和hashCode
方法,但是显然这不会给您的测试增加任何价值。琐碎地讲,您可以倒转会起作用的断言(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中看到,不建议使用这些部分模拟类的方法。