I wonder if you could break your functionnality (or test or both) in two parts:
- The random number generation (at least the part that belong in your code, not the standard API call I guess, unless you want to test that too). For example, you could have this code (or a more refined version, according to your technologies) :
The fact that you call your method must return a value that is not in the list.
public class RandomGenerator {
public int getValue() {
return `<random implementation>`;
}
}
public class RandomNewGenerator {
RandomGenerator randomGenerator = new RandomGenerator();
public int getValue(List<Integer> ints) {
// note that a Set<Integer> would be more efficient
while(true) {
Integer i = randomGenerator.getValue();
if (!ints.contains(i)) {
return i;
}
}
}
}
In real code, I would change stuff (use an interface, inject using Spring and so on)...
That way, in your test for RandomNewGenerator, you can override the RandomGenerator with an implementation that returns a known serie of values. You can then test your RandomNewGenerator without facing any random.
I believe this is indeed the spirit of JUnit tests, to make them simple, lightning fast, and even better : repeatable! This last quality actually allow your tests to be used as regression tests, which is so convenient.
Example test code:
public class RandomNewGeneratorTest {
// do the set up
private List<Integer> empties = ...//
private List<Integer> basics = ... // set up to include 1,2, 7, 8
private class Random extends RandomNewGenerator {
int current;
Random(int initial) {
current = initial;
}
public int getValue() {
return current++; // incremental values for test, not random
}
}
public void testEmpty() {
RandomNewGenerator randomNewGenerator = new RandomNewGenerator();
// do a simple injection of dependency
randomNewGenerator.randomGenerator = new Random(1);
// random starts at 1, builds up
assertEquals(1, randomNewGenerator.getValue(empties);
assertEquals(2, randomNewGenerator.getValue(empties);
assertEquals(3, randomNewGenerator.getValue(empties);
assertEquals(4, randomNewGenerator.getValue(empties);
}
public void testBasic() {
RandomNewGenerator randomNewGenerator = new RandomNewGenerator();
// do a simple injection of dependency
randomNewGenerator.randomGenerator = new Random(5);
// random starts at 5, builds up
// I expect 7, 8 to be skipped
assertEquals(5, randomNewGenerator.getValue(basics);
assertEquals(6, randomNewGenerator.getValue(basics);
assertEquals(9, randomNewGenerator.getValue(basics);
}
}
Note that this code is only a raw sample. You could alter it any way you need, for example by giving to the random generator a sequence of the values it must return. You could test for returning twice in a row the same number, for example.