mardi 3 février 2015

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?


Aucun commentaire:

Enregistrer un commentaire