如何设计可用于测试的伪随机数生成器模式?
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);
}
..这不是很好的做法,但它比改组测试和生产代码要好得多。
我目前正在开发一个相当大的应用程序,其中包括计算数学问题。计算是在类中进行的,我们称它们为 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);
}
..这不是很好的做法,但它比改组测试和生产代码要好得多。