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

在Maven/Gradle项目中,ScalaCheck+ScalaTest能否为Gen设置随机种子?

如何在ScalaTest+ScalaCheck中固定种子复现属性测试失败案例

问题场景

你在Maven/Gradle的Scala项目中使用ScalaTest+ScalaCheck做属性测试时遇到偶发失败,尝试通过Gen.apply(Parameters.default, Seed.apply(12345L))固定随机种子来复现失败案例,但这个操作无效,测试仍然使用随机生成的种子,错误输出如下:

TestFailedException was thrown during property evaluation.
Message: "" was not equal to "1"
Location: (MyTest.scala:21)
Occurred when passed generated values (
arg0 = Foo("", 0)
)
Init Seed: -8607081352353034494

原始测试代码:

import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers._
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks

class MyTest extends AnyFlatSpec with ScalaCheckPropertyChecks {

  it should "work" in {

    implicit val arbString = Arbitrary(Gen.alphaStr)
    implicit val arb: Arbitrary[Foo] = Arbitrary(Gen.resultOf(Foo))

    forAll { f: Foo =>
      println(f)

      f.a shouldBe "1"
    }
  }
}

case class Foo(a: String, b: Int)

你修改后的无效代码:

import org.scalacheck.Gen.Parameters
import org.scalacheck.rng.Seed
import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers._
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks

class MyTest extends AnyFlatSpec with ScalaCheckPropertyChecks {

  Gen.apply(Parameters.default, Seed.apply(12345L))

  it should "work" in {

    implicit val arbString = Arbitrary(Gen.alphaStr)
    implicit val arb: Arbitrary[Foo] = Arbitrary(Gen.resultOf(Foo))

    forAll { f: Foo =>
      println(f)

      f.a shouldBe "1"
    }
  }
}

case class Foo(a: String, b: Int)

为什么你的方法无效

Gen.apply(Parameters.default, Seed.apply(12345L))只是创建了一个单次使用的生成器实例,并没有全局覆盖ScalaTest+ScalaCheck的默认种子配置。forAll方法会使用自身的参数配置逻辑,完全不受这个孤立调用的影响。

正确的解决方法

方法1:针对单个测试用例固定种子(推荐)

直接在forAll调用中传入种子参数,这样只会影响当前测试用例,不会干扰其他测试:

import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers._
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks._

class MyTest extends AnyFlatSpec with ScalaCheckPropertyChecks {

  it should "work" in {

    implicit val arbString = Arbitrary(Gen.alphaStr)
    implicit val arb: Arbitrary[Foo] = Arbitrary(Gen.resultOf(Foo))

    // 使用失败输出中的种子值来复现问题
    forAll(initialSeed(-8607081352353034494L)) { f: Foo =>
      println(f)
      f.a shouldBe "1"
    }
  }
}

case class Foo(a: String, b: Int)

方法2:全局配置种子(适用于整个测试类)

如果需要让测试类中所有forAll都使用固定种子,可以重写scalacheckConfig方法:

import org.scalacheck.{Arbitrary, Gen}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers._
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import org.scalatestplus.scalacheck.PropertyCheckConfiguration

class MyTest extends AnyFlatSpec with ScalaCheckPropertyChecks {

  // 全局设置种子
  override val scalacheckConfig = PropertyCheckConfiguration(initialSeed = -8607081352353034494L)

  it should "work" in {

    implicit val arbString = Arbitrary(Gen.alphaStr)
    implicit val arb: Arbitrary[Foo] = Arbitrary(Gen.resultOf(Foo))

    forAll { f: Foo =>
      println(f)
      f.a shouldBe "1"
    }
  }
}

case class Foo(a: String, b: Int)

注意:直接使用错误输出中的Init Seed值,就能精准复现导致失败的那组测试数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 21:23:08