我正在开发一个应用程序,其中包括生成一组数据的生成阶段。生成涉及许多循环,其中一些循环生成随机数,以便决定如何继续。这意味着每次生成的数据集都不相同。
我正在尝试跟踪一些仅在特定条件下使用生成数据集发生的错误。鉴于有缺陷的数据集,我知道为什么应用程序中会出现错误,但我正在尝试解决的问题是生成阶段如何首先生成错误的数据集。然而,这不容易调试,因为99%的生成阶段不会生成错误的数据集。
由于这个原因,我希望有一种方法来记录和回放正在生成的数字,以重现发生错误的特定条件。我在网上搜索过这样的框架,但我还没有提出任何建议。不幸的是,“记录randoms”主要是关于随机记录的结果,而“可重复的randoms”返回主要是关于不可重复的RNG的结果!
我知道生成阶段的代码只调用java.util.Random.nextInt(int)
方法,这有点简化了问题。我开始考虑自己创建一个可重复的随机框架。
public class RepeatableRandom extends Random {
private static final Object LOCK = new Object();
private static final Random RANDOM = new Random();
private static enum Mode { PASSTHROUGH, RECORD, PLAYBACK; }
private static Mode mode = Mode.PASSTHROUGH;
// ...synchronized setters for each of the three modes...
private static Map<Integer,Integer> invocationCount = new HashMap<>();
private static Map<Integer,List<Integer>> randoms = new HashMap<>();
@Override
public int nextInt(int n) {
switch (mode) {
case Mode.PASSTHROUGH:
return RANDOM.nextInt(n);
case Mode.RECORD:
if (!randoms.containsKey(n)) {
randoms.put(n,new ArrayList<>());
}
int nextInt = RANDOM.nextInt(n);
randoms.get(n).put(nextInt);
return nextInt;
case Mode.PLAYBACK:
synchronized(LOCK) {
int i = invocationCount.get(n);
int nextInt = randoms.get(n).get(invocationCount);
invocationCount.put(n,i+1);
return nextInt;
}
}
}
public void loadRandomsFromFile(String filename) { //... }
public void saveRandomsToFile(String filename) { //... }
public void clear() { // ... }
}
在生成阶段用Random
替换所有对RepeatableRandom
的引用后,我会编写如下的测试代码:
RepeatableRandom.setRecordMode();
do {
RepeatableRandom.clear();
dataSet = generateDataSet();
while (!isBuggyDataSet(dataSet));
RepeatableRandom.saveRandomsToFile(FILENAME);
稍后,在我的代码中,我可以写:
RepeatableRandom.setPlaybackMode();
RepeatableRandom.clear();
RepeatableRandom.loadRandomsFromFile(FILENAME);
executeMainApplication();
然后我可以在调试模式下运行一系列断点,最后找出为什么生成这个特定的错误数据集。
但是我确信我不是第一个遇到这个问题的人。我觉得为这个用例创建一个全新的定制框架并不舒服。我觉得那里肯定有东西,但我找不到它!解决这类问题的正确方法是什么?
答案 0 :(得分:0)
你是否意识到你总是可以使用种子从同一个地方开始随机序列?创建新的Random时,您可以传入种子值,如果您使用相同的种子两次,那么您生成的数字每次都是相同的。
选择种子,运行测试,如果他们没有显示您之后的行为,则递增种子并再试一次。当你得到你想要的东西时,记下种子并从那时起始终使用那个数字。
答案 1 :(得分:-1)
开始时捕获随机种子,并在测试期间将其重置为相同的种子。您可能希望更改代码以依赖全局随机提供程序,然后您可以将此类策略附加到应用程序全局。