PACT - 使用提供者状态

时间:2017-09-12 18:26:54

标签: pact

我正在尝试使用pact来验证spring boot微服务。我已经从使用者生成了pact文件,并使用pact broker在提供者端验证了它。

我有另一个用例,我需要在根据实际服务响应验证pact文件之前执行一些代码。我阅读了有关状态更改URL和状态更改以及闭包来实现它,但无法获得如何实现此目的的示例。有人可以帮忙吗?

我的具体情况是:我创建了一个更新客户ID为1234的合同(名字:测试姓氏:用户)。

如果此客户不存在,那么我需要通过读取pact文件中更新请求的名字,姓氏,id以及通过状态更改的其他信息(城市,州,电话号码)将此数据插入到DB中码。

所以我的问题是,我可以通过状态更改从pact文件中读取请求数据,而不是在验证方面配置名字,姓氏和ID吗?

1 个答案:

答案 0 :(得分:6)

状态更改URL是您在提供程序上创建的挂钩,以允许Pact告知提供程序在测试开始时应该处于什么状态。在每次测试运行之前,模拟消费者会在提供程序上点击状态更改URL,并告诉它测试期望的状态名称。

你需要做两件事:

  1. 配置状态更改网址
  2. 在提供商
  3. 上实施状态更改端点

    配置状态更改URL

    您可以在提供商验证设置中配置状态更改网址。例如,使用the maven plugin

    <serviceProvider>
      <name>provider1</name>
      <stateChangeUrl>http://localhost:8080/tasks/pactStateChange</stateChangeUrl>
    ...
    

    或使用Gradle provider plugin

    hasPactWith('consumer1') {
     stateChangeUrl = url('http://localhost:8080/tasks/pactStateChange')
    ...
    

    这两个都告诉模拟使用者在每次测试之前使用localhost:8080/tasks/pactStateChange来改变提供者的状态。

    实施状态更改端点

    上面链接的文档告诉我们,默认情况下,请求的格式是状态字符串的POST请求和任何参数:

    { "state" : "a provider state description", "params": { "a": "1", "b": "2" } }
    

    要使用此功能,请在提供程序上实现类似以下未经测试的代码:

    @RequestMapping(value = "tasks/pactStateChange", method = RequestMethod.POST)
    ResponseEntity<?> stateChange(@RequestBody ProviderState state) {
       if (state.state == "no database") {
           // Set up state for the "no database" case here
       } else if state.state == "Some other state" {
           // Set up state here
       } else if  ...   // Other states go here
       ... 
       }
    
       return ResponseEntity.ok().build()
    }
    

    请原谅那个例子中的任何弹簧启动错误 - 我不是一个春季启动人员,但你可以看到一般原则。

    使用状态更改网址,pact不会告知提供商任何设置详细信息。它只是告诉提供者您在测试中使用的预先约定的状态字符串。这可能类似于"foo exists"。然后,在为状态更改URL实现处理程序时,您会检测"foo exists",并在那里进行任何显式设置。

    if (state.state == "foo exists") {
         // do whatever you need to set up so that foo exists
        repository.clear()
        repository.insert(new Foo("arguments that foo needs",12))
    }
    

    如果您想更多地了解提供者状态的意图,请阅读wiki page on provider states

    如何在特定情况下执行此操作

    你问:

      

    我可以通过状态更改从pact文件中读取请求数据,而不是在验证端配置名字,姓氏和ID吗?

    您可能会对合同测试的意图感到困惑 - 每个测试都是状态和请求的组合。

    所以不要用一个测试来说:

    • 我的测试是请求客户更新。如果客户存在,那么我期待X响应,如果不存在,那么我期待Y响应

    你用两个测试来说:

    • 当我向客户记录提交更新时(在客户存在的状态下),我希望X响应。

    • 当我向客户记录提交更新时(在客户不存在的状态下),我希望Y回复。

    这些测试是您的契约合同中的两个独立项目。

    目的不是在合同中包含设置的详细信息。在消费者方面,您的州只是一个字符串,上面写着“存在id = 1234的客户”字样。

    在提供程序端,您的状态更改端点会检测该URL并根据需要创建状态。这通常以硬编码的方式完成:

    if (state == "Customer with id=1234 exists") {
      Database.Clear()
      Database.Insert(new Customer(1234, "John","Smith")) 
    } else if (state == "No customers exist") { 
      Database.Clear()
    }
    

    您不希望通过解析状态字符串以参数化方式执行此操作,因为这样您就会在测试使用者和提供者之间创建新的复杂契约。

    消费者测试不应该知道如何设置提供者状态,他们应该只知道测试需要什么状态(仅限名称)。同样,提供者不需要知道正在测试什么,只需要知道如何将状态名称转换为实际状态。