Software random number generators are not random
They are deterministic if they are seeded with the same seed.
I also corrected the comparison logic to be correct in the range check.
Testable Implementation
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;
}
}
}
Deterministic Test
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));
}
}
No matter how many times you run this test it will always pass.
It is a trivial exercise for the reader to expand this to test for thousands or millions of inputs. As long as the seed is the same as when the test data is generated, it will pass when tested.
An injectable random number generator instance would be a better design and would make testing even easier in cases where the random number source is actually not deterministic.
static
methods are an anti-pattern and is the crux of your problem with testing as it stands, there is nothing here that can not be fixed with some simple refactoring to get rid of the static
stuff and make it deterministic and testable as my code shows.