karate - 从 Spock 运行 Karate(1.0.1) 测试时,在模拟中设置的系统属性最终在 karate.properties ['message' 中未定义]

标签 karate spock

在 Karate 版本 0.9.5 中,我能够在模拟调用期间使用 System.setProperty('message', message)。然后,使用 karate.properties['message'] 在功能中可以使用该属性。我已升级到版本 1.0.1,现在 karate.properties['message'] 的结果为未定义

Spock 测试代码

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiTestRunnerSpec extends Specification {

    @LocalServerPort
    private int port

    @SpringBean
    MessageLogger messageLogger = Mock()

    def "setup"() {
        System.out.println("Running on port: " + port)
        System.setProperty("server.port", "" + port)
    }

    def "Run Mock ApiTest"() {
        given:
        System.setProperty('foo', 'bar')

        when:
        Results results = Runner.path("classpath:").tags("~@ignore").parallel(5)

        then:
        results != null
        1 * messageLogger.logMessage(_ as String) >> { String message ->
            assert message != null
            System.setProperty("message", message)
        }
    }
}

Controller

@RestController
public class MessageController {

  @Autowired private MessageLogger messageLogger;

  @GetMapping("/message")
  public String message() {
    String message = "Important Message";

    messageLogger.logMessage(message);

    return message;
  }
}

消息记录器

@Component
public class MessageLogger {

  public void logMessage(String message) {
    System.out.println(message);
  }
}

Karate 配置.js

function fn() {
  karate.configure('connectTimeout', 10000);
  karate.configure('readTimeout', 10000);
  karate.configure('ssl', true);

  var config = {
    localUrl: 'http://localhost:' + java.lang.System.getProperty('server.port'),
  };
  print('localUrl::::::::::', config.localUrl);
  return config;
}

功能

@mockMessage
@parallel=true
Feature: Test Message

  Background:
    * url localUrl

  Scenario: GET

  Given path '/message'
  When method get
  Then status 200

  * print 'foo value ' + karate.properties['foo']
  * print 'message value ' + karate.properties['message']

0.9.5

2021-04-28 15:07:51.819 (...) [print] **foo value bar**
2021-04-28 15:07:51.826 (...) [print] **message value Important Message**

1.0.1

2021-04-28 14:36:58.566 (...) [print] **foo value bar** 
2021-04-28 14:36:58.580 (...) [print] **message value undefined** 

Link to project on github

最佳答案

我克隆了你的项目并注意到一些过时的东西(Groovy、Spock 和 GMaven+ 版本)。升级它们并没有改变结果,我仍然可以重现您的问题。

A 还注意到,在您的两个分支中,POM 的不同之处不仅在于 Karate 版本号,而且依赖项也不同。如果我使用 1.0.1 分支中的分支,测试将不再在 0.9.5 下运行。因此,我 fork 了您的项目,并向您发送了每个分支的两个拉取请求,其中依赖项设置对于两个 Karate 版本的工作方式相同。现在分支实际上只是 Karate 版本号不同:

https://github.com/kriegaex/spock-karate-example/compare/karate-0.9.5...kriegaex:karate-1.0.1

顺便说一句,由于某种原因,我必须编译运行 JDK 11 的代码,JDK 16 不起作用。 GMaven+ 提示 Java 16 groovy 类文件(字节码版本 60.0),尽管 GMaven+ 应该使用目标级别 11。不知道这是怎么回事。无论如何,在 Java 11 上我可以重现你的问题。由于两个分支的 Spock 版本是相同的,我猜问题出在 Karate 本身。我建议在那里打开一个问题,链接到您的 GitHub 项目(在您接受我的 PR 后)。 Spock 肯定设置了系统属性,我在 stub 关闭命令中添加了更多日志输出来验证这一点。也许这是一个关于 Karate 如何以及何时与史波克沟通的问题。


更新:Peter Thomas 在他的回答中建议将要传输到 Java 对象中的功能的值存储起来,并在 Spock 测试设置后从功能中访问该值。我猜,他的意思是这样的:

https://github.com/kriegaex/spock-karate-example/commit/ca88e3da

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiTestRunnerSpec extends Specification {

    @LocalServerPort
    private int port

    @SpringBean
    MessageLogger messageLogger = Mock() {
        1 * logMessage(_ as String) >> { String message ->
            assert message != null
            MessageHolder.INSTANCE.message = message
        }
    }

    def "setup"() {
        System.out.println("Running on port: " + port)
        System.setProperty("server.port", "" + port)
    }

    def "Run Mock ApiTest"() {
        given:
        Results results = Runner
          .path("classpath:")
          .systemProperty("foo", "bar")
          .tags("~@ignore")
          .parallel(5)

        expect:
        results
    }
    
    static class MessageHolder {
        public static final MessageHolder INSTANCE = new MessageHolder()
        private String message

        private MessageHolder() {}

        String getMessage() {
            return message
        }

        void setMessage(String message) {
            this.message = message
        }
    }
}
@mockMessage
@parallel=true
Feature: Test Message

  Background:
    * url localUrl

  Scenario: GET

  Given path '/message'
  When method get
  Then status 200

  * print 'foo value ' + karate.properties['foo']
  * def getMessage =
    """
    function() {
      var MessageHolder = Java.type('com.example.spock.karate.ApiTestRunnerSpec.MessageHolder');
      return MessageHolder.INSTANCE.getMessage();
    }
    """
  * def message = call getMessage {}
  * print 'message value ' + message

更新2:这是Peter的第二个想法的实现,即通过JS简单地访问Java系统属性。因此,我使用消息持有者单例简化了工作但不必要的复杂版本,再次消除了它:

https://github.com/kriegaex/spock-karate-example/commit/e235dd71

现在它看起来就像这样(类似于原始的 Spock 规范,只是重构得不那么冗长):

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ApiTestRunnerSpec extends Specification {

    @LocalServerPort
    private int port

    @SpringBean
    MessageLogger messageLogger = Mock() {
        1 * logMessage(_ as String) >> { String message ->
            assert message != null
            System.setProperty('message', message)
        }
    }

    def "setup"() {
        System.out.println("Running on port: " + port)
        System.setProperty("server.port", "" + port)
    }

    def "Run Mock ApiTest"() {
        expect:
        Runner.path("classpath:").systemProperty("foo", "bar").tags("~@ignore").parallel(5)
    }
}

唯一重要的变化是 Karate 功能:<​​/p>

@mockMessage
@parallel=true
Feature: Test Message

  Background:
    * url localUrl

  Scenario: GET

  Given path '/message'
  When method get
  Then status 200

  * print 'foo value ' + karate.properties['foo']
  * def getMessage = function() { return Java.type('java.lang.System').getProperty('message'); }
  * print 'message value ' + getMessage()

关于karate - 从 Spock 运行 Karate(1.0.1) 测试时,在模拟中设置的系统属性最终在 karate.properties ['message' 中未定义],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67307301/

相关文章:

html - 需要存储表的属性值以在 Karate 中进行断言

testing - 尝试验证模式时面对 java.lang.ClassNotFoundException : com. intuit.karate.demo.util.SchemaUtils

Groovy 和 Spock : toDouble vs toFloat

java - 非静态字段初始化

json - 在Spock中将模拟转换为JSON

Karate DSL - 在功能文件中使用 Java 包

karate - TypeError : karate. map is not a function - Karate

Karate 框架 : #notnull and #present are not working in case response is empty

groovy - Spock:可重用数据表

selenium - 如何排除 Geb 中的测试?