如何设计可用于测试的伪随机数生成器模式?

How to design a Pseudorandom Number Generator-Pattern which can be used for testing?

我目前正在开发一个相当大的应用程序,其中包括计算数学问题。计算是在类中进行的,我们称它们为 A 和 B,它们具有一些随机的最终属性和一个(唯一的)最终 int id 作为实例变量。

我希望能够在测试模式下运行程序,在每次执行中,随机变量完全相同,例如,允许我使用 Junit 将结果与手工计算进行比较测试。显然,我不想在每次代码更改后重新计算我的示例解决方案(例如,如果插入对 prng 的较早访问,这将移动所有随机数)。

请注意,我目前使用 Java.util.Random 作为 prng,但我愿意接受建议。

现在的问题是:我应该如何构建 prng 的实例化和访问?要指出问题,请注意以下方法是非常糟糕的方法:

我想到了以下解决方案(主要基于 this answer),但并不完全相同,因为编程语言和测试种子生成不同。

public class PRNGeneratorGenerator{

    //Make class a singleton
    private PRNGeneratorGenerator instance;
    private PRNGeneratorGenerator() {}
    public PRNGeneratorGenerator getInstance(){
        if (instance == null) instance = new PRNGeneratorGenerator();
        return instance;
    }

    //RandomNumberGenerator-Methods and Attributes
    private boolean isTestMode = false;
    private Random seedRng = new Random();

    public void setTestMode(boolean testMode){ 
       isTestMode = testMode; 
    }

    public Random getPseudorandomNumberGenerator(long testSeed){
      if(isTestMode) return new Random(testSeed); 
      return new Random(seedRng.nextLong());
    }
}

具有最终随机数的类(上面命名为 A 和 B)将如下所示:

public class A{
  private final static long CLASS_SEED = 872349;
  private final int randomNumberOne;
  private final int randomNumberTwo;
  private final int id;

  public A(int id){
    this.id = id;
    long testSeed = CLASS_SEED + id;
    Random rnd = PRNGeneratorGenerator.getInstance().getPseudorandomNumberGenerator(testSeed);
    randomNumberOne = rnd.nextInt();
    randomNumberTwo = rnd.nextInt();
  }
}

在测试模式下,我会在开始任何实例化之前调用 PRNGeneratorGenerator.getInstance().setTestMode(true)

这是解决我在 java 中的问题的好方法吗?或者这种方法有什么缺点吗?我已经阅读了许多类似的问题,但没有找到可以回答我的问题的等效问题。预先感谢您的回答。

我建议制作一个 class "PRNGeneratorGeneratorTest" 来创建自己的 PRNGeneratorGenerator 本地实例以进行测试。出于很多原因,混洗测试和生产代码是个坏主意:例如这很令人困惑,很容易在测试中留下一些东西,在不需要时打开模式等。测试 class 无论如何还有其他好处,例如让您能够进行所有测试同时在 1 个构建中自动显示和保存结果

如果不想做测试class,至少把getPseudorandomNumberGenerator分成2份(即做一个测试方法):

public Random getPseudorandomNumberGenerator(){
    return new Random(seedRng.nextLong());
}

public Random getPseudorandomNumberGeneratorTest(long testSeed){
    return new Random(testSeed); 
}

..这不是很好的做法,但它比改组测试和生产代码要好得多。