修改单元测试常量的推荐模式是什么?这是我目前使用的一段时间,今天我意识到它存在缺陷。
假设我的班级看起来像这样
class Foo {
private static final int MAX_TIME = Integer.getInteger("myProp", 1000);
...
}
我使用VM属性的事实不仅是在单元测试中修改它。这是因为我希望它从实际代码中不可变,我不想用它污染构造函数,因为它是一个实现细节。
所以,在制作中我希望超时1秒;但是对于单元测试来说太长了,所以我这样做了
class FooTest {
@Before
public void setUp() {
System.setProperty("myProp", "50");
}
@Test
public void testThatAssumesTimeoutOf50() { ... }
}
这很长时间以来一直很好,直到今天我终于添加了BarTest
这样的
class BarTest {
Foo mockFoo = mock(Foo.class); //actually done in a @Before method in the real code
}
现在创建的是我的测试失败或通过,具体取决于执行顺序。如果首先测试Foo
,则假定测试超时为50ms的测试通过。但是,如果首先测试Bar
,则会因为模拟而加载Foo
,因此MAX_TIME
采用默认值1000,然后BarTest
结束时{{1}假设测试超时为50ms的测试现在失败了。
答案 0 :(得分:0)
最简单的方法可能是删除final
关键字。这将允许您在类加载时间后更改值。
由于您在许多不同的类和可能的包中设置并获取值,因此您应该添加getter和setter。如果您需要跨包更改此值,则必须为public
。
class Foo{
public static int getMaxTime(){
return MAX_TIME;
}
public static void changeMaxTime(int timeout){
//validation logic goes here
this.MAX_TIME = timeout;
}
然后,在测试类中,您应该将旧值保存在@BeforeClass
或@Before
阶段,将其更改为您想要的任何值,然后在{{1}中恢复旧值}或@AfterClass
阶段。
因为看起来你在许多测试类中都这样做,所以最好自己制作一个Test Rule:
@After
}
然后在你的测试代码中:
public class TimeoutRule extends ExternalResource {
private final int oldTimeout, newTimeout;
public TimeoutRule(int timeout){
this.oldTimeout = Foo.getMaxTime();
this.newTimeout = timeout;
}
@Override
protected void before() {
}
@Override
protected void after() {
//restore old timeout
Foo.setMaxTimeOut(oldTimeout);
}
}
该代码会将超时重置为50 ms,然后在每次测试后将其恢复为原始值。如果您只希望每个测试类只执行一次,请改用class FooTest {
@Rule
public TimeoutRule timeoutRule = new TimeoutRule(50);
@Test
public void testThatAssumesTimeoutOf50() { ... }
(并创建字段@ClassRule
)