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

Scala中如何测试调用其他样例类的样例类并存根依赖返回值?

Scala样例类内部调用的存根实现方案

问题场景

你定义了两个Scala样例类:

case class First()  {
  def run() =
    callSecondCaseClass()
}
case class callSecondCaseClass()  {
     // 执行一些操作并返回结果
}

想要测试First类时,存根callSecondCaseClass让它返回指定模拟值,但当前测试写法无法实现,需要调整代码结构来解耦依赖。

核心问题

原代码中First的run方法直接在内部实例化callSecondCaseClass,属于硬编码依赖,Mock框架无法拦截这种直接创建的对象,必须先重构解耦。

解决方案步骤

1. 重构代码解耦依赖

首先定义抽象特质封装callSecondCaseClass的行为,然后让First通过构造函数接收该特质的实例(同时保留默认值兼容原有逻辑):

// 定义抽象特质,描述callSecondCaseClass的核心行为
trait SecondHandler {
  def perform(): String // 替换成你实际的返回类型
}

// 让原样例类实现该特质
case class CallSecondCaseClass() extends SecondHandler {
  override def perform(): String = {
    // 原有业务逻辑,返回结果
    "真实结果"
  }
}

// 修改First类,通过构造函数注入依赖
case class First(handler: SecondHandler = CallSecondCaseClass()) {
  def run() = handler.perform()
}

2. 编写测试代码(以Mockito为例)

创建SecondHandler的模拟实例,注入到First中,存根指定方法的返回值:

import org.mockito.Mockito._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatestplus.mockito.MockitoSugar

class FirstTest extends AnyFlatSpec with MockitoSugar {
  "First.run" should "返回存根的模拟值" in {
    // 创建模拟的SecondHandler
    val mockHandler = mock[SecondHandler]
    // 定义要返回的模拟值
    val stubValue = "模拟结果"
    // 存根perform方法返回指定值
    when(mockHandler.perform()).thenReturn(stubValue)
    
    // 传入模拟对象创建First实例
    val first = First(mockHandler)
    val result = first.run()
    
    // 验证结果符合预期
    assert(result == stubValue)
  }
}

如果使用ScalaMock,代码类似:

import org.scalamock.scalatest.MockFactory
import org.scalatest.flatspec.AnyFlatSpec

class FirstTest extends AnyFlatSpec with MockFactory {
  "First.run" should "使用存根的SecondHandler结果" in {
    val mockHandler = mock[SecondHandler]
    val stubValue = "模拟结果"
    
    (mockHandler.perform _).expects().returning(stubValue)
    
    val first = First(mockHandler)
    val result = first.run()
    
    assert(result == stubValue)
  }
}

原测试代码的问题

原代码中when(First.callSecondCaseClass).thenReturn(value)写法错误:

  • callSecondCaseClass是类名,不是First的成员方法,无法通过First.调用
  • 即使写法正确,First内部直接new对象的逻辑无法被Mock框架拦截,必须通过依赖注入让外部可以替换实例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:22:51