rpg711 linked above to a way to change a field using reflection, but I'd advise against it. Bear in mind that Java is allowed to inline static final fields per JLS 13.4.9:
If a field is a constant variable (§4.12.4), then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the usage of the field unless they are recompiled. This is true even if the usage itself is not a compile-time constant expression (§15.28)
It's also mentioned as a warning in JLS 17.5.3, as in the linked answer.
Beyond that, also remember that someone (perhaps a future you) will be reading the code someday and make the (very fair) assumption that the static final int
value will never change. You may be only changing it in the test, but that's still changing it, and you may be surprised at the behavior the next time you have to figure out why your test broke.
While you can relax the modifiers to make it a non-final protected static int
, I prefer either the "override for testing" or "overload for testing" method, depending on whether you like subclasses or visible-for-testing methods. Override-for-testing would look like this:
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() { /* ... */ }
}
...which is actually pretty efficient, because the JVM can inline the method. Overload-for-testing would look like this:
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. */
}
}
The former can be nice if you don't mind the override, but the latter is particularly handy if you're a fan of dependency injection. Both benefit from package-private visibility if you put your system-under-test and test in the same package (even if they're in different source trees). Note that either way, you give the API an obvious and easy default, but you make it clear that there's a way to get different behavior. Tests are consumers of your components, and letting them modify behavior through the API (instead of through a back door) can help you define the behavior of your components.