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

如何用MockFactory模拟含嵌套case class的Scala配置类?

解决ScalaMock模拟嵌套Case Class的空指针问题

刚好我之前也遇到过类似的场景,直接mock外层case class时,嵌套属性默认返回null,访问自然会触发空指针异常。下面给你两种简洁的解决方案,适配不同的测试需求:

1. 完全Mock嵌套结构(适合需要验证调用的场景)

如果你的测试需要验证嵌套配置的方法/属性是否被调用,就分别mock外层和内层的case class,然后关联它们的返回关系。

假设你的case class结构是这样的:

case class ProxyConfig(host: String, port: Int)
case class SomeConfig(proxy: ProxyConfig, ftpPath: String, httpTimeout: Int)

测试代码示例:

import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalamock.scalatest.MockFactory

class ConfigTest extends AnyFlatSpec with Matchers with MockFactory {
  it should "mock nested case class without NPE" in {
    // 第一步:模拟内层的ProxyConfig
    val mockProxy = mock[ProxyConfig]
    // 设置ProxyConfig属性的返回值
    (mockProxy.host _).expects().returning("test-proxy.example")
    (mockProxy.port _).expects().returning(8080)

    // 第二步:模拟外层的SomeConfig,并关联嵌套属性
    val mockSomeConfig = mock[SomeConfig]
    // 让mock的SomeConfig返回刚才创建的mockProxy
    (mockSomeConfig.proxy _).expects().returning(mockProxy)
    // 同时设置其他属性的返回值
    (mockSomeConfig.ftpPath _).expects().returning("/test/ftp/dir")
    (mockSomeConfig.httpTimeout _).expects().returning(5000)

    // 现在访问嵌套属性不会有空指针了
    mockSomeConfig.proxy.host shouldBe "test-proxy.example"
    mockSomeConfig.proxy.port shouldBe 8080
  }
}

2. 使用Stub简化配置(适合仅需要假数据的场景)

如果你的测试不需要验证调用,只是需要一个能正常返回值的假配置,用stub代替mock会更简洁——stub不需要写expects(),直接用returns设置返回值即可:

it should "use stub for nested case class" in {
    // 创建内层ProxyConfig的stub
    val stubProxy = stub[ProxyConfig]
    stubProxy.host _ returns "stub-proxy.example"
    stubProxy.port _ returns 9090

    // 创建外层SomeConfig的stub并关联
    val stubSomeConfig = stub[SomeConfig]
    stubSomeConfig.proxy _ returns stubProxy
    stubSomeConfig.ftpPath _ returns "/stub/ftp/path"

    // 验证返回值
    stubSomeConfig.proxy.host shouldBe "stub-proxy.example"
}

为什么之前会有空指针?

当你直接mock[SomeConfig]时,ScalaMock对所有引用类型的属性默认返回null。当代码尝试访问someConfig.proxy.host时,proxy是null,自然就触发了空指针异常。解决的核心就是给外层mock的proxy属性设置一个有效的返回值——不管是另一个mock、stub,甚至是真实的ProxyConfig实例都可以。

比如如果不需要模拟ProxyConfig,直接用真实实例也能快速解决:

val realProxy = ProxyConfig("real-proxy", 8080)
val mockSomeConfig = mock[SomeConfig]
(mockSomeConfig.proxy _).expects().returning(realProxy)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:13:53