当方法将函数作为参数时 Mockito 验证失败

Mockito verify fails when method takes a function as argument

我有一个 Scala 测试,它使用 Mockito 来验证是否调用了某些 DataFrame 转换。我把它分解成这个简单的有问题的例子

import org.apache.spark.sql.DataFrame
import org.scalatest.funsuite.AnyFunSuite
import org.apache.spark.sql.functions._
import org.mockito.{Mockito, MockitoSugar}

class SimpleTest extends  AnyFunSuite{

  def withGreeting(df: DataFrame):DataFrame = {
    df.withColumn("greeting", lit("hello"))
  }

  test("sample test") {
    val mockDF = MockitoSugar.mock[DataFrame]
    val mockDF2 = MockitoSugar.mock[DataFrame]
    MockitoSugar.doReturn(mockDF2).when(mockDF).transform(withGreeting)
    mockDF.transform(withGreeting)
    val orderVerifier = Mockito.inOrder(mockDF)
    orderVerifier.verify(mockDF).transform(withGreeting)
  }

}

我试图断言转换是在我的 mockDF 上调用的,但它失败了

Argument(s) are different! Wanted:
dataset.transform(<function1>);
-> at org.apache.spark.sql.Dataset.transform(Dataset.scala:2182)
Actual invocations have different arguments:
dataset.transform(<function1>);

为什么在这种情况下验证会失败?

您需要将 transform 的 lambda 表达式参数保存为 val 以便正确测试并将其传递给所有 transform 调用:

def withGreeting(df: DataFrame):DataFrame = {
  df.withColumn("greeting", lit("hello"))
}

test("sample test") {
  val mockDF = MockitoSugar.mock[DataFrame]
  val mockDF2 = MockitoSugar.mock[DataFrame]
  val withGreetingExpression = df => withGreeting(df)
  MockitoSugar.doReturn(mockDF2).when(mockDF).transform(withGreetingExpression)
  mockDF.transform(withGreetingExpression)
  val orderVerifier = Mockito.inOrder(mockDF)
  orderVerifier.verify(mockDF).transform(withGreetingExpression)
}

Mockito 需要为模拟函数调用提供相同(或相等)的参数。当您传递 lambda 表达式而不保存每次调用时 transform(withGreeting) 创建新对象 Function[DataFrame, DataFrame]

transform(withGreeting)

等同于:

transform(new Function[DataFrame, DataFrame] {
  override def apply(df: DataFrame): DataFrame = withGreeting(df)
})

并且它们彼此不相等 - 这是错误消息的原因: Argument(s) are different!

例如尝试执行:

println(((df: DataFrame) => withGreeting(df)) == ((df: DataFrame) => withGreeting(df))) //false

您可以在 java 中阅读更多关于对象相等性的信息(在 scala 中它是相同的):