在Gradle中,如何在每次执行JUnit测试类之前设置唯一的系统属性?

时间:2017-12-09 20:23:18

标签: gradle junit

在下面的gradle脚本中,maxParallelForksforkEvery将使用每个Junit测试类的新JVM启动一个新进程。 有没有办法让每个测试进程/ JVM / Junit类都有自己独特的系统属性?

我尝试了一个实验,我在beforeSuite方法中将UUID值作为系统属性传递。

apply plugin:'java'
test {
    ignoreFailures = true
    maxParallelForks = 8
    forkEvery = 1
    systemProperty 'some.prop', 'value'

   beforeSuite { descriptor ->
    logger.lifecycle("Before suite: " + descriptor)
    def theuuid = UUID.randomUUID().toString()
    println "beforeSuite uuid =" + theuuid
    systemProperty 'some.uuid', theuuid
   }
   beforeTest { descriptor ->
      logger.lifecycle("Running test: " + descriptor)
   }
}
repositories {
    mavenCentral()
}
dependencies {
    testCompile 'junit:junit:4.12'
}

JUnit测试类LoginTest1LoginTest2在测试方法中打印出系统属性。

public class LoginTest1 {
    private String userName="Gradle";
@Test
    public void testUserName() throws Exception {
        System.out.println("LoginTest1: Testing Login ");

        System.out.println("LoginTest1: Testing Login some.prop -> " 
           + System.getProperty("some.prop"));
        System.out.println("LoginTest1: Testing Login some.uuid -> " 
           + System.getProperty("some.uuid"));

    assertTrue(userName.equals("Gradle"));
    }
}
public class LoginTest2 {
    private String userName="Gradle";

@Test
    public void testUserName() throws Exception {
        System.out.println("LoginTest2: Testing Login ");

        System.out.println("LoginTest2: Testing Login some.prop -> " 
           + System.getProperty("some.prop"));
        System.out.println("LoginTest2: Testing Login some.uuid -> " 
           + System.getProperty("some.uuid"));

    assertTrue(userName.equals("Gradle"));
        }
}

从下面的gradle输出中可以看出,在运行单个JUnit测试方法之前调用了beforeSuite方法。两个测试类都获得6a006689-474f-47d5-9649-a88c92b45095

的相同系统属性
 $ gradle clean test

> Task :test 
Before suite: Gradle Test Run :test
beforeSuite uuid =6a006689-474f-47d5-9649-a88c92b45095
Before suite: Gradle Test Executor 1
beforeSuite uuid =39edb608-3027-4ad8-bd15-f52f50175582
Before suite: Test class ch6.login.LoginTest1
beforeSuite uuid =c0ce55e0-924c-4319-becb-bc27229c9cf3
Before suite: Gradle Test Executor 2
beforeSuite uuid =c15eaac0-7ea7-46d2-8235-8dc49b3f7a39
Running test: Test testUserNameNotNull(ch6.login.LoginTest1)
Before suite: Test class ch6.login.LoginTest2
beforeSuite uuid =73abbe24-5b78-4935-867a-445ac4ac20ef
Running test: Test testUserName(ch6.login.LoginTest1)
Running test: Test testUserName(ch6.login.LoginTest2)

JUnit测试类输出:

LoginTest1: Testing Login 
LoginTest1: Testing Login some.prop -> value
LoginTest1: Testing Login some.uuid -> 6a006689-474f-47d5-9649-a88c92b45095

LoginTest2: Testing Login 
LoginTest2: Testing Login some.prop -> value
LoginTest2: Testing Login some.uuid -> 6a006689-474f-47d5-9649-a88c92b45095

看起来有一个对beforeSuite的初始调用(看作":test"),然后每个Test Executor调用一次。所有JVM都设置了第一个uuid值(" 6a006689")。 我可以使用简单的beforeClass方法吗?

在下面的调试日志中,看起来测试执行器被赋予jvm参数-Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095,并且使用soley来创建新的JVM(根据forkEvery配置)。这让我觉得在Gradle中我不想做的事情。

20:23:42.466 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'Gradle Test Executor 1'. Working directory: /a/b/ Command: /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.security.manager=worker.org.gradle.process.internal.worker.child.BootstrapSecurityManager -Dorg.g
radle.native=false -Dsome.prop=value -Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095 -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea -cp /data/.gradle/caches/4.3.1/workerMain/gradle-worker.jar worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 1'

20:23:42.466 [INFO] [org.gradle.process.internal.DefaultExecHandle] Starting process 'Gradle Test Executor 2'. Working directory: /a/b/ Command: /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Djava.security.manager=worker.org.gradle.process.internal.worker.child.BootstrapSecurityManager -Dorg.g
radle.native=false -Dsome.prop=value -Dsome.uuid=6a006689-474f-47d5-9649-a88c92b45095 -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -ea -cp /data/.gradle/caches/4.3.1/workerMain/gradle-worker.jar worker.org.gradle.process.internal.worker.GradleWorkerMain 'Gradle Test Executor 2'

更新8/2018

以下解决方案在Gradle 4.9及更高版本

中不起作用

相反,有一个org.gradle.test.worker系统属性,您可以使用它来区分worker,计算显示名称,临时目录等。这个test.worker只是一个增加的long值。 Gradle团队没有计划让测试工作者可配置。很遗憾因为我必须在我的测试代码中进行一些重大的重构才能升级Gradle。 " @ BeforeAllCallback"在JUnit 5中可能对你有用。

试图通过拦截Test.copyTo(JavaForkOptions目标)来解决

此代码演示了lance-java的建议,并成功回答了我的问题。 我有以下build.gradle脚本,它使用MyTestTask来扩展Test并添加一个名为my_uuid的唯一值。请注意,构建脚本必须具有forkEvery = 1,以确保每个JUnit测试调用copyTo一次:

class MyTestTask extends Test {

 public Test copyTo(JavaForkOptions target) {
        super.copyTo(target);
      String uuid = UUID.randomUUID().toString();
        System.out.println("MyTestTask copyTo:\n my_uuid=" +  uuid);
        System.out.println("\t before getJvmArgs:" +  target.getJvmArgs());
        System.out.println("\t before getSystemProperties:" +  target.getSystemProperties());

        target.systemProperty("my_uuid", uuid);

        System.out.println("\t after getJvmArgs:" +  target.getJvmArgs());
        System.out.println("\t after getSystemProperties:" +  target.getSystemProperties());

        return this;
    }

}
///

subprojects {
    apply plugin: 'java'

    repositories {
        mavenCentral()
    }

    dependencies {
        testCompile 'junit:junit:4.12'
    }


    test {
        enabled false // This doesn't seem to matter.

    }

    task my_test(type: MyTestTask) {

        forkEvery 1 // need this so copyTo called each JUnit test

        testLogging.showStandardStreams = true

        doFirst {
            def uuid = UUID.randomUUID().toString()
            println "TEST:Task name is $name. In doFirst. uuid is " + uuid

            jvmArgs '-Dcommon_uuid='+ uuid

        }
    }
}

执行的Junit测试非常简单,只需打印出System.getProperty(" my_uuid")和System.getProperty(" common_uuid")。

> Task :CustomCopyToSubProject:my_test 
TEST:Task name is my_test. In doFirst. uuid is eed1ee92-7805-4b8e-a74c-96218d1be6e1
MyTestTask copyTo:
MyTestTask copyTo:
 my_uuid=a7996c20-1085-4397-9e32-fd84467dcb45
 my_uuid=69f6f347-71d0-4e5d-9fad-66bf4468fab3
         before getJvmArgs:[]
         before getJvmArgs:[]
         before getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1]
         before getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1]
         after getJvmArgs:[]
         after getJvmArgs:[]
         after getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1, my_uuid:69f6f347-71d0-4e5d-9fad-66bf4468fab3]
         after getSystemProperties:[common_uuid:eed1ee92-7805-4b8e-a74c-96218d1be6e1, my_uuid:a7996c20-1085-4397-9e32-fd84467dcb45]

ch3.LoginTest2 > testUserName2 STANDARD_OUT
    LoginTest2.java: Testing Login !  >>---> my_uuid=a7996c20-1085-4397-9e32-fd84467dcb45 common_uuid=eed1ee92-7805-4b8e-a74c-96218d1be6e1

ch3.LoginTest1 > testUserName1 STANDARD_OUT
    LoginTest1.java: Testing Login !  >>---> my_uuid=69f6f347-71d0-4e5d-9fad-66bf4468fab3 common_uuid=eed1ee92-7805-4b8e-a74c-96218d1be6e1

task my_test中的common_uuiddoFirstMyTestTask.copyTo方法设置了自己的my_uuid。 您可以从输出中看到MyTestTask被调用两次,每个JUnit测试任务一次(LoginTest1和LoginTest2)。两个JUnit测试在my_uuid中获得了自己独特的系统属性。

2 个答案:

答案 0 :(得分:0)

由于为每个测试分叉了一个新的JVM,你可以使用一个用UUID初始化的静态字段。

public class Helper {
    public static final String uuid = UUID.randomUUID().toString();
}

public class LoginTest2 {
    private String userName="Gradle";

    @Test
    public void testUserName() throws Exception {
        System.out.println("LoginTest2: Testing Login ");

        System.out.println("LoginTest2: Testing Login some.uuid -> " 
           + Helper.uuid;

        assertTrue(userName.equals("Gradle"));
    }
}

答案 1 :(得分:0)

我认为您想要拦截Test.copyTo(JavaForkOptions target),遗憾的是我能看到这样做的唯一方法是延长Test

例如

public class Test2 extends org.gradle.api.tasks.testing.Test {
    public Test copyTo(JavaForkOptions target) {
        super.copyTo(target);
        target.systemProperty("uuid", UUID.randomUUID().toString());
        return this;
    }
}

的build.gradle

apply plugin: 'java'
test {
    enabled = false
}
task test2(type: Test2) {
    // guessing you'll need to configure a bit of stuff here
}
check.dependsOn test2