Reputation: 9706
I have 2 integration tests implemented with JUnit. Both of the tests perform calls to the remote server and the server target is configured by environment variable:
System.setProperty("property", "value1");
The tricky thing is that those properties must be different for 2 tests. If I set the environment variable for each unit test it does not work, because the middleware that we are using caches the property value on first call and does not evaluate it anymore (for the second test).
I believe the solution could be to run those unit tests in separate processes. I saw similar discussion here, but maybe there is more elegant way fo doing this with JUnit4? This problem looks pretty common. Or maybe there are another ways to run unit tests with different configuration?
Thanks in advance for any advices.
Upvotes: 5
Views: 5842
Reputation: 873
I needed to isolate junit tests during work with some legacy code so I developed small maven plugin Jute which allows to start every Junit test method in separated external process, I have published it in GitHub and in maven central, may be the plugin would be appropriate solution for your question, also the plugin allows to start such tests with different JVMs
Upvotes: 3
Reputation: 1495
Using the ProcessBuilder API, you could alter your environment variables just before launching each process. Here's a code snippet how you might do that.
@Test
void testVariant1(){
String [] commandArray =
{"java", "-cp", "your/class/path", "org.mydomain.myClass", ...};
Map<String, String> envVarsForThisTest = new HashMap<String, String>();
envVarsForThisTest.put("newProperty", "value1");
List<String> staleVars = new List<String>();
stateVars.add("oldProperty");
File workingDir = new File("myDir"));
Process p = runVariant(
commandArray, envVarsForThisTest, staleVars, workingDir);
Assert.assert(p.waitFor(), 0);
checkAssertions(p.getOutputStream(), p.getErrorStream());
}
void checkAssertions(OutputStream output, InputStream errorStream){
// where you'll check the return values against your expectations
}
void runVariant(String commandArray[],
Map<String,
String> newEnvironmentVariables,
List<String> environemntVariablesToRemove,
File workingDirectory){
ProcessBuilder pb = new ProcessBuilder(commandArray);
Map<String, String> env = pb.environment();
for(Map.Entry<String, String> entry : newEnvironmentVariables){
env.put(entry.key(), entry.value());
}
for(String staleVariable : environemntVariablesToRemove){
env.remove(staleVariable);
}
pb.directory(workingDirectory);
return pb.start();
}
Upvotes: 0
Reputation: 69663
Unit tests should generally not depend on external resources like a remote server. Otherwise you are not testing the unit but the availability and correctness of the resource it relies on.
So how can such units be tested?
You usually do this with mock objects. You encapsulate the calls to the external resource in an object and pass this object to the unit you want to test (that's called dependency injection). In your unit test you don't pass a real server abstraction object. You are instead passing a mock object which implements the same interface or extends the server abstraction class. The mock object does not really query the server. Instead it immediately returns the value the server should return.
This likely requires some refactoring of your code. But it allows your unit-test to work without relying on an external resource. It also makes the test much, much faster which reduces the overall execution time of your test suit. This allows you to perform unit tests much more frequently
Upvotes: -2
Reputation: 115328
It depends on how are you running JUnit.
If you want to be able to run it either from IDE or from build implement your custom Runner
and mark test case using annotation RunWith(MyRunner.class)
.
If you are using maven and it is enough for you to be able to run test from there use <forkMode>always</forkMode>
into maven-surefire-plugin
definition.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.11</version>
<configuration>
<systemProperties>
<systemProperty>
<name>panpwr.conf.dir</name>
<value>${basedir}/conf-test</value>
</systemProperty>
</systemProperties>
<forkMode>always</forkMode>
Upvotes: 3
Reputation: 533492
It is considered bad practice to have state which cannot be reset between tests. While code which cannot be tested easily is common, the solutions are not simple.
I would consider resetting the cached value even if you have use reflections to do it. Exactly what needs to be reset depends on the internal representation of the library.
Upvotes: 3