如何在单独的进程中运行JUnit测试?

时间:2012-09-03 10:11:27

标签: java junit

我有两个使用JUnit实现的集成测试。两个测试都执行对远程服务器的调用,服务器目标由环境变量配置:

System.setProperty("property", "value1");

棘手的是,对于2次测试,这些属性必须不同。如果我为每个单元测试设置环境变量它不起作用,因为我们使用的中间件在第一次调用时缓存属性值而不再评估它(对于第二次测试)。

我相信解决方案可能是在单独的流程中运行这些单元测试。我看到了类似的讨论here,但是使用JUnit4可能有更优雅的方式吗?这个问题看起来很常见。 或者可能还有其他方法可以使用不同的配置运行单元测试?

提前感谢任何建议。

5 个答案:

答案 0 :(得分:3)

在测试之间具有无法重置的状态被认为是不好的做法。虽然无法轻松测试的代码很常见,但解决方案并不简单。

我会考虑重置缓存的值,即使你有使用反射来做。究竟需要重置的内容取决于库的内部表示。

答案 1 :(得分:2)

这取决于你如何运行JUnit。

如果您希望能够从IDE运行它,或者从构建实现自定义Runner并使用注释RunWith(MyRunner.class)标记测试用例。

如果你正在使用maven,那么就可以从那里运行测试,并使用<forkMode>always</forkMode>进入maven-surefire-plugin定义。

        <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>

                

答案 2 :(得分:1)

我需要在使用某些遗留代码时隔离junit测试,因此我开发了一个小型maven插件Jute,它允许在分离的外部进程I have published it in GitHubmaven central中启动每个Junit测试方法,可能是插件将是适合您的问题的解决方案,插件也允许使用不同的JVM启动此类测试

答案 3 :(得分:0)

使用ProcessBuilder API,您可以在启动每个进程之前更改环境变量。这是一个代码片段,您可以如何做到这一点。

 @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();
 }

答案 4 :(得分:-1)

单元测试通常不应依赖于远程服务器等外部资源。否则,您不会测试该单元,而是测试它所依赖的资源的可用性和正确性。

那么如何测试这些单位呢?

您通常使用模拟对象执行此操作。您将对外部资源的调用封装在对象中,并将此对象传递给您要测试的单元(称为dependency injection)。在单元测试中,您不传递真正的服务器抽象对象。您正在传递一个实现相同接口的模拟对象或扩展服务器抽象类。模拟对象并不真正查询服务器。相反,它会立即返回服务器应返回的值。

这可能需要对您的代码进行一些重构。但它允许您的单元测试在不依赖外部资源的情况下工作。它还使测试更快,更快,从而减少了测试套装的总体执行时间。这使您可以更频繁地执行单元测试