最近,我遇到了一个问题,我不得不编写一种方法的测试,该方法需要计算在一定可能性范围内的随机分布值1 。 更准确地说,如果您假设签名看起来像
interface RandomRangeValueCalculator {long calculateRangeValue( long center, long radius );
}
测试可能会验证以下2个 :
public class RandomRangeValueCalculatorImplTest {@Testpublic void testCalculateRangeValue() {long center = [...];long radius = [...];RangeValueCalculator calculator = [...];long actual = calculator.calculateRangeValue( center, radius );assertTrue( center + radius >= actual );assertTrue( center - radius <= actual );}
}
但是,多次计算相同的中心和半径的范围值将返回不同的结果(至少在大多数情况下)。 因此,从某种意义上来说,解决方案在某种程度上是脆弱的,即实施不善可能会轻易导致间歇性故障。 另一方面,我不想深入到实际破坏值分配的深度。 后者(随机,高斯等)由协作者提供,并且其正确用法已经通过其他测试确认。
在我看来,一种更为实用的解决方案是实际上一次又一次地自动运行上述测试,以使其更加“有意义”。 当然,最简单的方法是将测试的内容放入一个循环中并继续进行下去。
但是从一开始,将断言放在一个循环中并将两个方面混合到一个测试运行中似乎有些不对。 更为重要的是,涵盖的问题域需要进行更多种类的测试。 因此,出于减少冗余的意图,我记得关于JUnit-Rules的帖子,并实现了一个简单的重复规则3 。 有了这个规则,上面的测试可以轻轻地修改为:
public class RandomRangeValueCalculatorImplTest {@Rulepublic RepeatRule repeatRule = new RepeatRule();@Test@Repeat( times = 10000 )public void testCalculateRangeValue() {long center = [...];long radius = [...];RangeValueCalculator calculator = [...];long actual= calculator.calculateRangeValue( center, radius );assertTrue( center + radius >= actual );assertTrue( center - radius <= actual );}
}
我认为很容易理解,在运行测试用例时, testCalculateRangeValue
方法将执行10000次。 以下代码片段显示了RepeatRule的实现,这很简单:
public class RepeatRule implements TestRule {@Retention( RetentionPolicy.RUNTIME )@Target( {java.lang.annotation.ElementType.METHOD} )public @interface Repeat {public abstract int times();}private static class RepeatStatement extends Statement {private final int times;private final Statement statement;private RepeatStatement( int times, Statement statement ) {this.times = times;this.statement = statement;}@Overridepublic void evaluate() throws Throwable {for( int i = 0; i < times; i++ ) {statement.evaluate();}}}@Overridepublic Statement apply(Statement statement, Description description ){Statement result = statement;Repeat repeat = description.getAnnotation( Repeat.class );if( repeat != null ) {int times = repeat.times();result = new RepeatStatement( times, statement );}return result;}
}
到目前为止,RepeatRule达到了目的,并且基于上述实现的系统功能正在发挥作用。 尽管如此,有时有人会为树木而错过森林,所以我认为分享此解决方案以了解其他人的想法可能是个好主意。
- 实际上,这只是问题领域的一部分,但我认为这是这篇文章的充分动机。 ↩
- Formalistically口语:F(N,M)∈{E |e≥nm∧e≤n+ M},对于所有的E,N,米ℕ∈ ↩
- 简短的google搜索只想出了Spring可用的类似解决方案,而我的库集中没有。 ↩
翻译自: https://www.javacodegeeks.com/2013/04/running-junit-tests-repeatedly-without-loops.html