Java 测试使用随机值的类

Java 测试使用随机值的类,java,junit,Java,Junit,我需要测试一个使用random.nextDouble()的类。有没有优雅的方法来提供测试这些数字,以便能够预见执行的输出?是的,有:使用种子随机数 您应该向类中添加一个额外的包私有构造函数,以允许该类为其随机变量获取种子。在该构造函数中,而不是编写 random = new Random(); 写 初始化私有字段随机。通过,可以从种子初始化随机变量的内部状态。由于随机数实际上不是随机数,而是一个伪随机数生成器,它的下一个返回值基于当前状态,因此通过设置初始状态,可以确定地将一系列调用返回的数字

我需要测试一个使用random.nextDouble()的类。有没有优雅的方法来提供测试这些数字,以便能够预见执行的输出?

是的,有:使用种子随机数

您应该向类中添加一个额外的包私有构造函数,以允许该类为其随机变量获取种子。在该构造函数中,而不是编写

random = new Random();

初始化私有字段
随机
。通过,可以从种子初始化随机变量的内部状态。由于随机数实际上不是随机数,而是一个伪随机数生成器,它的下一个返回值基于当前状态,因此通过设置初始状态,可以确定地将一系列调用返回的数字序列设置为随机数


在测试代码中,使用此特殊包专用测试构造函数而不是默认构造函数初始化
Foo
类型的新对象,只要您每次都通过相同的种子,您正在测试的类每次都将获得相同的伪随机数序列。

我建议将随机数生成器嵌入到单独的组件中,并将其注入到您的类中。因此,您将能够在测试中注入其模拟实例。在我看来,这是最优雅的解决方案。您还可以使用反射和重写在类主体中创建的随机生成器来实现一些技巧,但这一点并不推荐。

您的测试试图证明什么?该
nextDouble
实际返回特定值?对我来说,这似乎不是一个很有用的测试

在这种情况下,您所能做的最好的事情就是证明,如果您多次运行代码,每次都会得到不同的随机数。在1000的循环中运行它,并将结果存储在某种类型的
Set
中。然后断言
集合的大小与循环的迭代次数相同


要想做得更好,就需要准确地量化“随机”的含义。整本书都是关于这一点写的,在单元测试中尝试和做这件事并不是一件真正有用的事情。

+1:尽管播种RNG是有效的(@Adam的答案),IMO模拟是一个更干净的解决方案,因为它避免了隐藏状态。为什么(接受)测试概率算法没有用?我很高兴你问到了。自动化测试(比如JUnit)的一部分要点是,您可以经常运行它,并且知道如果软件按照规范工作,那么测试就会通过。对一系列随机数施加的任何条件(例如,至少40%的随机数必须落在允许范围的一半内)都可以合法地失败——事实上,如果程序正常工作,偶尔也会失败。因此,如果您希望每次运行JUnit测试时都能通过测试,就无法在JUnit测试中表示“这些数字是随机的”。当然,您可以测试生成的数字。。。。。。通过特定的算法(如
random.nextDouble
),但不可能反映系统的业务需求;因此不应该是你正在测试的东西。唯一合理的做法是在
随机数
周围放置一个包装,存根包装,然后在生成随机数后测试它是否发生了正确的事情。感谢您的详细说明。对一个总是终止的拉斯维加斯算法进行验收测试怎么样?如果一个随机算法可能返回不同的值,但所有结果都必须满足某些标准,那该怎么办?我认为使用自动JUnit测试来测试拉斯维加斯算法是否给出了正确的结果是合适的。为了验证它是否能很好地使用资源,最好运行几次,并对您感兴趣的任何资源进行一些分析。也就是说,这是一个手动的特别测试,而不是一个自动的测试——您不希望每次在项目中运行JUnit测试时都重复它。在您提到的第二个案例中,只需对结果是否满足“特定标准”进行JUnit测试;我认为你们不应该进行随机试验。
random = new Random(seed);