rpg711 将above 链接到一种使用反射更改字段的方法,但我建议不要这样做。请记住,Java 允许inline static final fields per JLS 13.4.9:
如果一个字段是一个常量变量(第 4.12.4 节),那么删除关键字 final 或更改其值不会因为导致它们不运行而破坏与预先存在的二进制文件的兼容性,但它们不会看到任何新值除非重新编译,否则该字段的使用。即使用法本身不是编译时常量表达式也是如此(第 15.28 节)
在JLS 17.5.3 中也将其作为警告提及,如在linked answer 中。
除此之外,还要记住有人(也许是未来的你)有一天会阅读代码并做出(非常公平的)static final int 值永远不会改变的假设。您可能只是在测试中更改它,但它仍然在更改,下次您必须弄清楚测试失败的原因时,您可能会对这种行为感到惊讶。
虽然您可以放宽修饰符以使其成为非最终的protected static int,但我更喜欢“测试覆盖”或“测试重载”方法,具体取决于您是否喜欢子类或可见的测试方法。 Override-for-testing 看起来像这样:
public class YourComponent {
protected int getRequestTimeframeMilliseconds() {
return 600000;
}
}
public class YourComponentTest {
private static class YourComponentForTesting extends YourComponent {
@Override protected int getRequestTimeframeMilliseconds() {
return 500;
}
}
@Test public void shouldTimeout() { /* ... */ }
}
...实际上非常高效,因为 JVM 可以inline the method。测试重载看起来像这样:
public class YourComponent {
public static final int DEFAULT_REQUEST_TIMEFRAME_MILLISECONDS = 600000;
public ReturnObject callService() {
return callService(DEFAULT_REQUEST_TIMEFRAME_MILLISECONDS);
}
/** Package-private for testing. */
ReturnObject callService(int timeframe) {
/* Your implementation here. */
}
}
如果您不介意覆盖,前者可能会很好,但如果您是依赖注入的粉丝,后者特别方便。如果您将被测系统和测试放在同一个包中(即使它们位于不同的源代码树中),两者都将从包私有可见性中受益。请注意,无论哪种方式,您都为 API 提供了一个明显且简单的默认值,但您明确表示有一种方法可以获得不同的行为。测试是组件的消费者,让他们通过 API(而不是通过后门)修改行为可以帮助您定义组件的行为。