鉴于功能:
static boolean chance(int percentage) {
return percentage != 0 && random.nextInt(101) <= percentage;
}
并测试该功能:
@Test
public void chance_AlwaysFalse_Percentage0() {
assertFalse(chance(0));
}
该测试并未确定机会总是会返回true。我可以将change
函数更改为以下内容:
static boolean chance(int percentage) {
return random.nextInt(101) <= percentage;
}
并且测试仍然会通过。但是,random.nextInt(100)
返回0的可能性非常小,这会使函数返回true,从而使测试失败。
我也可以执行这个测试十亿次,但考虑到随机数的性质,失败的可能性很小。
我应该如何测试这样的功能?它应该进行测试吗?有什么更好的解决这个问题的方法?
答案 0 :(得分:2)
java中有一些功能可用于可重复的单元测试:
new Random(13)
将始终提供相同的随机数序列。这已被利用来查找以1,2,3,...,10开头的随机序列。或某些人的字母名称。Clock.fixed
答案 1 :(得分:0)
自动化测试无法捕获所有内容。事实上,你的函数的第一个示例也可能有一个错误,因为chance(1)
将有2%的几率而不是1%的几率返回true
(因为如果随机数为0或1,它将返回true
。但如果你只测试0和100,那么它将在100%的时间内通过这些测试。 (实际上,0和100是唯一的值,它们将返回true
正确的时间百分比;其他所有值将减少1%。该bug的影响是微妙的您可能会或可能不会注意到它,具体取决于函数的使用方式。)
如果你真的想要,你可以将你的测试放在一个循环中。如果你运行chance_AlwaysFalse_Percentage0
测试10,000次,则几率非常有利于被击中的任何特定随机数。 (不,它在技术上没有保证,但如果你计算赔率,我认为你会感到满意。)我不确定这是否值得。
答案 2 :(得分:0)
如果用相同的种子播种,它们是确定性的。 我还在范围检查中纠正了比较逻辑是正确的。
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Random;
@ParametersAreNonnullByDefault
public class Q47336122
{
private final Random random;
public Q47336122(final long seed)
{
this.random = new Random(seed);
}
public boolean chance(final int percentage)
{
if (percentage <= 0) { return false; }
else if (percentage >= 100) { return true; }
else
{
final int r = this.random.nextInt(100);
return r > 0 && r <= percentage;
}
}
}
import org.junit.Test;
import javax.annotation.ParametersAreNonnullByDefault;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@ParametersAreNonnullByDefault
public class Q47336122Test
{
@Test
public void testChance()
{
final Q47336122 q = new Q47336122(1000L);
/* poor man's code generator */
// for (int i=0; i <= 100; i++) {
// System.out.println(String.format("assertThat(q.chance(%d),is(%s));", i, q.chance(i)));
// }
assertThat(q.chance(0),is(false));
assertThat(q.chance(1),is(false));
assertThat(q.chance(2),is(false));
assertThat(q.chance(3),is(false));
assertThat(q.chance(4),is(false));
assertThat(q.chance(5),is(false));
assertThat(q.chance(6),is(false));
assertThat(q.chance(7),is(false));
assertThat(q.chance(8),is(false));
assertThat(q.chance(9),is(false));
assertThat(q.chance(10),is(false));
assertThat(q.chance(11),is(false));
assertThat(q.chance(12),is(false));
assertThat(q.chance(13),is(false));
assertThat(q.chance(14),is(false));
assertThat(q.chance(15),is(false));
assertThat(q.chance(16),is(false));
assertThat(q.chance(17),is(false));
assertThat(q.chance(18),is(true));
assertThat(q.chance(19),is(false));
assertThat(q.chance(20),is(false));
assertThat(q.chance(21),is(false));
assertThat(q.chance(22),is(false));
assertThat(q.chance(23),is(false));
assertThat(q.chance(24),is(true));
assertThat(q.chance(25),is(false));
assertThat(q.chance(26),is(false));
assertThat(q.chance(27),is(false));
assertThat(q.chance(28),is(false));
assertThat(q.chance(29),is(false));
assertThat(q.chance(30),is(false));
assertThat(q.chance(31),is(false));
assertThat(q.chance(32),is(false));
assertThat(q.chance(33),is(false));
assertThat(q.chance(34),is(false));
assertThat(q.chance(35),is(false));
assertThat(q.chance(36),is(true));
assertThat(q.chance(37),is(false));
assertThat(q.chance(38),is(true));
assertThat(q.chance(39),is(false));
assertThat(q.chance(40),is(true));
assertThat(q.chance(41),is(false));
assertThat(q.chance(42),is(true));
assertThat(q.chance(43),is(false));
assertThat(q.chance(44),is(false));
assertThat(q.chance(45),is(false));
assertThat(q.chance(46),is(false));
assertThat(q.chance(47),is(false));
assertThat(q.chance(48),is(false));
assertThat(q.chance(49),is(false));
assertThat(q.chance(50),is(true));
assertThat(q.chance(51),is(true));
assertThat(q.chance(52),is(false));
assertThat(q.chance(53),is(true));
assertThat(q.chance(54),is(false));
assertThat(q.chance(55),is(true));
assertThat(q.chance(56),is(false));
assertThat(q.chance(57),is(true));
assertThat(q.chance(58),is(false));
assertThat(q.chance(59),is(false));
assertThat(q.chance(60),is(true));
assertThat(q.chance(61),is(false));
assertThat(q.chance(62),is(false));
assertThat(q.chance(63),is(true));
assertThat(q.chance(64),is(true));
assertThat(q.chance(65),is(true));
assertThat(q.chance(66),is(true));
assertThat(q.chance(67),is(true));
assertThat(q.chance(68),is(true));
assertThat(q.chance(69),is(false));
assertThat(q.chance(70),is(false));
assertThat(q.chance(71),is(true));
assertThat(q.chance(72),is(true));
assertThat(q.chance(73),is(true));
assertThat(q.chance(74),is(true));
assertThat(q.chance(75),is(false));
assertThat(q.chance(76),is(true));
assertThat(q.chance(77),is(true));
assertThat(q.chance(78),is(true));
assertThat(q.chance(79),is(false));
assertThat(q.chance(80),is(true));
assertThat(q.chance(81),is(false));
assertThat(q.chance(82),is(true));
assertThat(q.chance(83),is(true));
assertThat(q.chance(84),is(true));
assertThat(q.chance(85),is(true));
assertThat(q.chance(86),is(true));
assertThat(q.chance(87),is(true));
assertThat(q.chance(88),is(true));
assertThat(q.chance(89),is(true));
assertThat(q.chance(90),is(true));
assertThat(q.chance(91),is(true));
assertThat(q.chance(92),is(true));
assertThat(q.chance(93),is(true));
assertThat(q.chance(94),is(true));
assertThat(q.chance(95),is(true));
assertThat(q.chance(96),is(true));
assertThat(q.chance(97),is(true));
assertThat(q.chance(98),is(true));
assertThat(q.chance(99),is(true));
assertThat(q.chance(100),is(true));
}
}
无论你运行多少次测试,它都会一直通过。
对于读者来说,扩展它以测试成千上万的输入是一项微不足道的练习。只要种子与生成测试数据时相同,它就会在测试时通过。
可注射随机数生成器实例将是一个更好的设计,并且在随机数源实际上不确定的情况下会使测试更容易。
static
方法是反模式的,并且是测试问题的关键所在,这里没有任何东西无法通过一些简单的重构来解决static
正如我的代码所示,并使其具有确定性和可测试性。