sprinter
sprinter

Reputation: 27966

Mocking random numbers

My application uses a genetic algorithm for evolving neural networks. In developing unit tests for the (randomised) mutation algorithm I wish to ensure that for given random values the correct mutations occur.

In the question here the most popular answer to the question of unit testing algorithms that involve randomness is to use mocking. This seems very sensible to me but my question is whether anyone has solid suggestions about how to do this.

Here is how I currently achieve this. I define an interface for my randomness generator (highly simplified here for illustration purposes):

public interface Mutator {
    float randomSynapseWeightChange();
    float randomSynapseThresholdChange();
}

In the main application this interface has an implementation that wraps Random. In my unit testing framework I use:

public class TestMutator implements Mutator {
    List<Float> synapseWeightChanges = new ArrayList<>();
    public void addTestSynapseWeightChange(float weightChange) {
        synapseWeightChanges.add(weightChange);
    }
    public float randomSynapseWeightChange() {
        return synapseWeightChanges.remove();
    }
}

My unit tests then look like:

@Test
public void testDecreaseSynapseWeightMutation() {
    TestMutator mutator = new TestMutator();
    mutator.addTestSynapseWeightChange(-0.5);
    world.setMutator(mutator);
    Synapse synapse = new Synapse(new Neuron(), 0.1);
    synapse.mutate();
    assertEquals("Weight has decreased during mutation", -0.4, synapse.getWeight());
}

This is really not a particularly elegant solution. The unit test relies on knowing how many random numbers the code is going to need. For tests that involve several mock random numbers being pushed onto the list it pretty unclear when reading it later what each of the numbers of for.

So my question is has anyone come across a neater way of doing this? Would I be better off having an enum to define the different domains of randomness (or even different classes of Mutators) to document the meaning of the mocked numbers better?

Upvotes: 4

Views: 10954

Answers (1)

fge
fge

Reputation: 121750

Use a mock framework such as mockito. With it you can do this:

// static import for Mockito.xxx needed

final Mutator mutator = mock(Mutator.class);

// Will return value1, then value2
when(mock.randomSynapseWeightChange())
    .thenReturn(value1)
    .thenReturn(value2)
    .etc().etc();

You can even cook your own Answers if you need to return a more "complex" set of numbers than just specifying them all (for instance you want to cycle through a list of specified numbers).

Note that with the .thenReturn() example above, if you call the method three times then the returned values will be v1, v2, v2; four times, v1, v2, v2, v2. Etc etc. In short, the "last return" wins when no other is specified.

And then you can even check the number of invocations:

verify(mutator, times(3)).randomSynapseWeightChange();

Upvotes: 5

Related Questions