如何通过Gradle和-D为我的测试提供系统属性

141

我有一个Java程序,它读取一个系统属性。

System.getProperty("cassandra.ip");

我有一个Gradle构建文件,我从这里开始

gradle test -Pcassandra.ip=192.168.33.13
或者
gradle test -Dcassandra.ip=192.168.33.13

然而System.getProperty总是返回null

我发现的唯一方法是通过在我的Gradle构建文件中添加以下内容:

test {
    systemProperty "cassandra.ip", "192.168.33.13"
}

如何通过-D选项来实现?


1
当您使用 gradle -Dcassandra.ip=192.168.33.13 时会发生什么?无论如何,测试任务会分叉一个或多个新的JVM。因此,您必须显式地传递属性。但是没有人强制您在构建中硬编码它们的值。 - JB Nizet
还可以查看这个答案:https://dev59.com/EmAg5IYBdhLWcg3wWp7-#23689696 - IgalS
7个回答

175

-P参数用于gradle属性,而-D参数用于JVM属性。由于测试可能会在新的JVM中分叉,因此传递给gradle的-D参数不会传递到测试中 - 这似乎是您看到的行为。

您可以像所做的那样在test块中使用systemProperty,但是可以基于传入的gradle属性通过使用-P与其一起传递。

test {
    systemProperty "cassandra.ip", project.getProperty("cassandra.ip")
}

或者,如果您是通过 -D 参数传递它

test {
    systemProperty "cassandra.ip", System.getProperty("cassandra.ip")
}

2
这对我不起作用(在Java代码中使用System.getProperties().stringPropertyNames().forEach(System.out::println);进行测试,它没有出现) - CLOVIS
警告:如果未找到属性,则getProperty会抛出MissingPropertyException。请改用Eron的答案:https://dev59.com/b2Ei5IYBdhLWcg3wUK2C#43112126 - Yngvar Kristiansen
3
将默认值添加到gradle.properties可以避免MissingPropertyException异常。 - Duncan Calvert
我无法让这两种方法都起作用。无论我做什么,myProperty始终为空。包括下面提到的所有方法。我在想这是否与更近期的版本有关,因为所有评论都是来自2018年?@CLOVIS你找到解决方案了吗? - Hester Lyons
@HesterLyons 我只是想知道构建是测试还是正常运行,所以我使用了 gradle 在测试时添加的属性;你可以在这里看到代码:https://github.com/CLOVIS-AI/wildfyre-java/blob/master/src/main/java/net/wildfyre/http/Request.kt#L309 - CLOVIS

34

我遇到了这个问题,但我不想在gradle脚本中再次列出命令行上给定的所有属性。因此,我将所有系统属性发送到我的测试。

task integrationTest(type: Test) {
    useTestNG()
    options {
        systemProperties(System.getProperties())
    }
}

1
在执行此操作时要小心。如果系统属性在调用期间发生更改,可能会轻松破坏Gradle的最新检查。 - thokuest
对于JavaExec任务也是一样的。属性在任务中存在,但在Java程序中不存在,除非在任务中再次设置。 - Dinu Nicolae

13

我有一个案例,需要将多个系统属性传递给测试JVM,但不是全部属性(不想传递无关属性)。根据以上答案,并使用subMap来过滤我所需的属性,这对我起作用:

task integrationTest(type: Test) {
    // ... Do stuff here ...
    systemProperties System.getProperties().subMap(['PROP1', 'PROP2'])
}
在这个例子中,只有PROP1PROP2会在Gradle的JVM中存在时传递。

10

以下是一种变体,它将众多项目属性作为系统属性传递给测试JVM。 我更喜欢使用项目属性而不是系统属性来增加灵活性。

task intTest(type: Test) {
    systemProperties project.properties.subMap(["foo", "bar"])
}

可以通过命令行传递:

 $ gradle intTest -Pfoo=1 -Pbar=2

并在你的测试中检索得到:

String foo = System.getProperty("foo");

在使用subMap方法运行System.getProperty("someprop")时,我得到了{someprop=foo}而不是foo。我不得不在build.gradle中使用systemProperty "foo", project.properties.subMap(["foo"]).get("foo") - Yngvar Kristiansen
@YngvarKristiansen,你是在哪里(如何)使用 systemProperty "foo"?也就是说,我想看看这个代码行的完整内容。我尝试了这个问题中提出的所有建议,但Gradle仍然没有传递任何参数。希望这个可以解决问题! - Hester Lyons
@HesterLyons 对不起,我没有保存我的代码,所以我也不知道了:\ 我同意它看起来很不合适。 - Yngvar Kristiansen
谢谢@YngvarKristiansen。我后来发现我的问题是由于junit gradle插件引起的,该插件包含在我的gradle.build中。非常奇怪。 - Hester Lyons

2

这是我成功的经验

//in build.gradle file

    tasks.withType(Test) {
        systemProperties = [
           ip: System.getProperty('ip', '192.168.33.13'),
        ]
    }

    task integrationTests(type: Test){
        useTestNG()
    }

假设您正在使用TestNG,您可以像下面所示添加注释@Parameters

  public class IpAddress {
    @Test
    @Parameters("ip")
    public void printIpAddress(String ip) {
        System.out.println(ip);
    }
 }

现在您可以执行gradlew命令。
./gradlew clean -Dip="xx.xx.xx.xx" integrationTests --tests "IpAddress"

如果您想使用@DataProvider传递测试数据,则可以像下面这样传递,并执行与上面相同的gradle命令来运行测试。
 public class IpAddress {
    @DataProvider(name = "GetIP")
    private static Object[][] getIp() {
        return new Object[][]{
                //if -Dip is not provided in command, then by default it gets the value assigned in build.gradle file i.e.'192.168.33.13'
                {System.getProperty("ip")}, 
        };
    }

    @Test(dataProvider = "GetIP")
    public void printIpAddress(String ip) {
        System.out.println(ip);
    }
}

2

今天我也遇到了这个问题,对我有用的解决方法如下:

ext.env='prod'
test {
  systemProperty 'env', System.properties['env'] ?: "${env}"
  println "# test environment: " + systemProperties['env']
  ...
}

我使用-Penv=dev调用我的测试任务,如果我没有发送任何值,则在我的打印中获得'dev'值,这是我期望的行为。
通过System.getProperty("env"),也可以在Java端访问值。
我的结论是输入值(参数)实际上存储在System下,因此可以通过System.properties['env']System.getProperty("env")进行访问,而输出(系统属性)存储在systemProperties数组中,可以通过systemProperties['env']进行读取。

请替我工作,谢谢。在我这种情况下,我需要通过系统属性将Github令牌传递给测试。 - Jadson Santos

0
在我的情况下,我需要通过系统属性将Github令牌传递给测试。
我尝试过这个:
systemProperty "github.token", System.getProperty("github.token")

但是会给我一个错误,所以我传递了一个默认值:

ext.github_token='TOKEN'
test {
    systemProperty 'github.token', System.properties['github.token'] ?: "${github_token}"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接