模拟随机数
Mocking random numbers
我的应用程序使用遗传算法来进化神经网络。在为(随机化的)变异算法开发单元测试时,我希望确保对于给定的随机值,正确的变异会发生。
在问题 here 中,涉及随机性的单元测试算法问题的最流行答案是使用模拟。这对我来说似乎很明智,但我的问题是是否有人对如何做到这一点有可靠的建议。
以下是我目前的实现方式。我为我的随机生成器定义了一个 interface
(为了便于说明,此处进行了高度简化):
public interface Mutator {
float randomSynapseWeightChange();
float randomSynapseThresholdChange();
}
在主应用程序中,此接口有一个包装 Random
的实现。在我的单元测试框架中,我使用:
public class TestMutator implements Mutator {
List<Float> synapseWeightChanges = new ArrayList<>();
public void addTestSynapseWeightChange(float weightChange) {
synapseWeightChanges.add(weightChange);
}
public float randomSynapseWeightChange() {
return synapseWeightChanges.remove();
}
}
我的单元测试看起来像:
@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());
}
这确实不是一个特别优雅的解决方案。单元测试依赖于知道代码将需要多少个随机数。对于涉及将多个模拟随机数推入列表的测试,稍后阅读时很不清楚每个数字的用途。
所以我的问题是有没有人遇到过更简洁的方法?我会更好地使用枚举来定义不同的随机域(或者甚至不同的 类 的 Mutators)以更好地记录模拟数字的含义吗?
使用 mock 框架,例如 mockito。有了它你可以这样做:
// 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();
如果您需要 return 一组比指定所有数字更多的 "complex" 数字(例如,您想循环指定号码的列表)。
请注意,对于上面的 .thenReturn()
示例,如果调用该方法三次,则 returned 值将为 v1、v2、v2;四次,v1,v2,v2,v2。等等等等。简而言之,"last return"在没有指定其他时获胜。
然后你甚至可以检查调用次数:
verify(mutator, times(3)).randomSynapseWeightChange();
我的应用程序使用遗传算法来进化神经网络。在为(随机化的)变异算法开发单元测试时,我希望确保对于给定的随机值,正确的变异会发生。
在问题 here 中,涉及随机性的单元测试算法问题的最流行答案是使用模拟。这对我来说似乎很明智,但我的问题是是否有人对如何做到这一点有可靠的建议。
以下是我目前的实现方式。我为我的随机生成器定义了一个 interface
(为了便于说明,此处进行了高度简化):
public interface Mutator {
float randomSynapseWeightChange();
float randomSynapseThresholdChange();
}
在主应用程序中,此接口有一个包装 Random
的实现。在我的单元测试框架中,我使用:
public class TestMutator implements Mutator {
List<Float> synapseWeightChanges = new ArrayList<>();
public void addTestSynapseWeightChange(float weightChange) {
synapseWeightChanges.add(weightChange);
}
public float randomSynapseWeightChange() {
return synapseWeightChanges.remove();
}
}
我的单元测试看起来像:
@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());
}
这确实不是一个特别优雅的解决方案。单元测试依赖于知道代码将需要多少个随机数。对于涉及将多个模拟随机数推入列表的测试,稍后阅读时很不清楚每个数字的用途。
所以我的问题是有没有人遇到过更简洁的方法?我会更好地使用枚举来定义不同的随机域(或者甚至不同的 类 的 Mutators)以更好地记录模拟数字的含义吗?
使用 mock 框架,例如 mockito。有了它你可以这样做:
// 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();
如果您需要 return 一组比指定所有数字更多的 "complex" 数字(例如,您想循环指定号码的列表)。
请注意,对于上面的 .thenReturn()
示例,如果调用该方法三次,则 returned 值将为 v1、v2、v2;四次,v1,v2,v2,v2。等等等等。简而言之,"last return"在没有指定其他时获胜。
然后你甚至可以检查调用次数:
verify(mutator, times(3)).randomSynapseWeightChange();