unit testing with code that depends on environment variable
We have small set of environment variables exposed to control our application behavior. Application code is in java. (Environment variables may be evil, but the have a purpose in this special case)
What is the best way to unit test this? How can I create environment variables, set it to different values and call the tests repeatedly?
Current solution is to use env element in junit tasks . For example below
<env key="BASE_PLUGINS_FOLDER" value="c:/temp"/>
code sets environment vari开发者_Python百科able for the test. (This works only when fork mode is set to true)
This means I have to create multiple test sections in ant build file and corresponding test else where. This could become unmanageable pretty fast.
I feel there could be a better way, that is fully a junit-java code. Not sure how.
You should encapsulate how you retrieve these variables. Not only will it allow you to change the way you pass them around (env variable, system properties, configuration file, etc...) but it will also more testable.
Then you can define two different implementations: one that actually reads the environment (which you use in production) and one where you can specify these values yourself in Java (which you use in your tests).
Here is a hack given by my friend..
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
theEnvironmentField.setAccessible(true);
@SuppressWarnings({"unchecked"}) // this will be a Map or the test will fail if Java internals are changed
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
env.put(name, val);
// now System.getenv will return what we want
//noinspection CallToSystemGetenv
assertEquals("Problems setting up environment variable for test: " + name, val, System.getenv(name));
I fear this is a useless, frustrating answer... but consider redesigning the app to allow overriding the environment variables.
All access to them would need to be funneled through one place, which would also look for your choice of config mechanism -
-D,
or property file,
or property file pointed at by -D,
or runtime-created config object passed by test setup,
or smoke signals,
or ...
This can be solved using System Stubs (https://github.com/webcompere/system-stubs) in JUnit 4 and JUnit 5:
JUnit 4:
@Rule
public EnvironmentVariablesRule env = new EnvironmentVariablesRule("BASE_PLUGINS_FOLDER", "/tmp/something");
@Test
public void test() {
// variable is set here
}
Or in JUnit 5:
@ExtendWith(SystemStubsExtension.class)
class SomeTest {
@SystemStub
private EnvironmentVariables env = new EnvironmentVariables("BASE_PLUGINS_FOLDER", "/tmp/something");
@Test
void envSetHere() {
// environment variable is set
}
}
精彩评论