You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ScalaMock模拟按名称调用的函数?

解决ScalaMock模拟按名称调用函数的问题

你的问题出在两个关键地方:类型转换错误和返回值不符合方法签名,咱们一步步来修正:

错误原因分析

  1. 按名称参数的类型误解:f: => T是Scala的按名称参数,运行时它对应的是Function0[T](也就是() => T),而不是你写的() => Either[ErrorCode,T]。你把传入的futureFunction()的返回值(Future[Int])当成了Either类型,这就导致了类型转换异常。
  2. 返回值不匹配:myFunction的返回类型是Either[ErrorCode, T],但你直接返回了f()的结果(Future[Int]),没有包装成Either,这也不符合方法的签名要求。

修正后的测试代码

我们可以用两种方式来实现正确的mock,推荐第二种更类型安全的写法:

写法1:通用类型匹配(适合任意T)

import scala.concurrent.{Future, Await}
import scala.concurrent.duration._
import scala.util.Random
import org.specs2.mutable.Specification
import org.scalamock.scalatest.MockFactory

// 假设你的ErrorCode定义如下
sealed trait ErrorCode
case object UnknownError extends ErrorCode

class MyTest extends Specification with MockFactory {
  trait MyTrait {
    def myFunction[T](id: Int, name: String)(f: => T): Either[ErrorCode, T]
  }

  def futureFunction(): Future[Int] = Future {
    Thread.sleep(Random.nextInt(500))
    10
  }

  "Mock MyTrait" should {
    "execute the call-by-name parameter and return wrapped result" in {
      val mockTrait = mock[MyTrait]

      // 正确匹配按名称参数并处理
      (mockTrait.myFunction(_: Int, _: String)(_: => T))
        .expects(25, "test", *)
        .onCall { args =>
          // 提取按名称参数对应的Function0[T]
          val callByNameFunc = args.productElement(2).asInstanceOf[() => T]
          // 执行函数并包装成Right返回,符合方法签名
          Right(callByNameFunc())
        }

      // 调用mock方法,注意需要等待Future完成
      val result = mockTrait.myFunction(25, "test")(futureFunction())
      val finalValue = Await.result(result.right.get, 1.second)
      finalValue mustEqual 10
    }
  }
}

写法2:指定具体类型(更安全,避免类型转换)

如果你的测试场景中T是固定的(比如这里是Future[Int]),可以直接指定类型,这样不需要用productElement做类型转换,代码更清晰:

// ... 其他代码不变
(mockTrait.myFunction(_: Int, _: String)(_: => Future[Int]))
  .expects(25, "test", *)
  .onCall { (id, name, f) =>
    // f就是按名称参数,直接调用就会执行futureFunction()
    Right(f)
  }
// ... 断言部分不变

关键要点总结

  • 按名称参数f: => T在ScalaMock中用_: => T来匹配,运行时对应Function0[T]。
  • 必须保证mock的返回值符合原方法的签名:Either[ErrorCode, T],所以要用Right(...)包装执行结果。
  • 因为futureFunction()返回Future[Int],所以myFunction的返回值是Either[ErrorCode, Future[Int]],需要用Await.result等待Future完成后再断言数值。

内容的提问来源于stack exchange,提问作者earlymorningtea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:09:56