2017-01-03 32 views
0

我試圖定義使用Spring的雲合同這樣的CDC合同:爲可能的空數組定義合同?

org.springframework.cloud.contract.spec.Contract.make { 
    request { 
     method 'GET' 
     url $(client(~/\/categories\?publication=[a-zA-Z-_]+?/), server('/categories?publication=DMO')) 
    } 
    response { 
     status 200 
     headers { 
      header('Content-Type', 'application/json;charset=UTF-8') 
     } 
     body """\ 
      [{ 
       "code": "${value(client('DagKrant'), server(~/[a-zA-Z0-9_-]*/))}", 
       "name": "${value(client('De Morgen Krant'), server(~/[a-zA-Z0-9_\- ]*/))}", 
       "sections" : [] 
      }, 
      { 
       "code": "${value(client('WeekendKrant'), server(~/[a-zA-Z0-9_-]*/))}", 
       "name": "${value(client('De Morgen Weekend'), server(~/[a-zA-Z0-9_\- ]*/))}", 
       "sections" : [ 
        { 
        "id" : "${value(client('a984e824'), server(~/[0-9a-f]{8}/))}", 
        "name" : "${value(client('Binnenland'), server(~/[a-zA-Z0-9_\- ]*/))}" 
        } 
       ] 
      }] 
     """ 
    } 
} 

在生成的測試中,這將導致以下斷言:

DocumentContext parsedJson = JsonPath.parse(response.getBody().asString()); 
assertThatJson(parsedJson).array().contains("code").matches("[a-zA-Z0-9_-]*"); 
assertThatJson(parsedJson).array().array("sections").contains("id").matches("([0-9a-f]{8})?"); 
assertThatJson(parsedJson).array().array("sections").contains("name").matches("[a-zA-Z0-9_\\- ]*"); 
assertThatJson(parsedJson).array().contains("name").matches("[a-zA-Z0-9_\\- ]*"); 

但在我的測試中我想允許節數組是空的,就像第一個例子。現在,如果我的測試實現返回空節數組,則生成的測試失敗,因爲它無法爲空數組找到節的ID。

Parsed JSON [[{"code":"WeekendKrant","name":"De Morgen Weekend","sections":[]}]] 
doesn't match the JSON path [$[*].sections[*][?(@.id =~ /([0-9a-f]{8})?/)]] 

我也試圖與可選的(),但唯一不同的是,正則表達式包含「?」最後。 JSON斷言仍然失敗。

在存根中,兩個結果都會返回,但對於測試,我希望測試也能成功。測試斷言純粹是在每個屬性的最後一次出現時生成的嗎?有沒有可能在數組上有'optional()'之類的東西?

回答

2

直到版本1.0.3.RELEASE這樣的額外檢查是不可能的。自該版本以來,您可以提供更多匹配器 - http://cloud.spring.io/spring-cloud-static/spring-cloud-contract/1.0.3.RELEASE/#_dynamic_properties_in_matchers_sections。您可以將byType與額外的尺寸檢查相匹配。

從文檔摘自:

目前我們支持與下列匹配的可能性基於JSON唯一路徑的匹配。對於stubMatchers:

byEquality() - 從通過所提供的JSON路徑的響應而採取的值需要等於在合同

byRegex所提供的值(...) - 由通過響應而採取的值所提供的JSON路徑需要匹配正則表達式

byDate() - 從通過所提供的JSON路徑的響應而採取的值需要匹配ISO日期

byTimestamp()中的正則表達式 - 從響應而採取的值通過提供的JSON路徑需要匹配ISO日期時間的正則表達式

byTime() - 從通過所提供的JSON路徑的響應而採取的值需要匹配ISO時間

正則表達式對於testMatchers:

byEquality() - 經由所述響應而採取的值提供JSON路徑需要等於在合同

byRegex(...)所提供的值 - 從通過所提供的JSON路徑的響應而採取的值需要匹配正則表達式

byDate() - 該值從通過公關回應ovided JSON路徑需要匹配ISO日期

byTimestamp()中的正則表達式 - 從通過所提供的JSON路徑的響應而採取的值需要匹配正則表達式的ISO的DateTime

byTime() - 從所採取的值通過提供的JSON路徑的響應需要與ISO時間的正則表達式相匹配。byType() - 通過提供的JSON路徑從響應中獲取的值需要與在主體中定義的類型具有相同的類型合同中的迴應。 byType可以設置閉包,您可以設置minOccurrence和maxOccurrence。這樣你就可以斷言集合的大小。

而且例如:

Contract contractDsl = Contract.make { 
request { 
    method 'GET' 
    urlPath '/get' 
    body([ 
      duck: 123, 
      alpha: "abc", 
      number: 123, 
      aBoolean: true, 
      date: "2017-01-01", 
      dateTime: "2017-01-01T01:23:45", 
      time: "01:02:34", 
      valueWithoutAMatcher: "foo", 
      valueWithTypeMatch: "string" 
    ]) 
    stubMatchers { 
     jsonPath('$.duck', byRegex("[0-9]{3}")) 
     jsonPath('$.duck', byEquality()) 
     jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) 
     jsonPath('$.alpha', byEquality()) 
     jsonPath('$.number', byRegex(number())) 
     jsonPath('$.aBoolean', byRegex(anyBoolean())) 
     jsonPath('$.date', byDate()) 
     jsonPath('$.dateTime', byTimestamp()) 
     jsonPath('$.time', byTime()) 
    } 
    headers { 
     contentType(applicationJson()) 
    } 
} 
response { 
    status 200 
    body([ 
      duck: 123, 
      alpha: "abc", 
      number: 123, 
      aBoolean: true, 
      date: "2017-01-01", 
      dateTime: "2017-01-01T01:23:45", 
      time: "01:02:34", 
      valueWithoutAMatcher: "foo", 
      valueWithTypeMatch: "string", 
      valueWithMin: [ 
       1,2,3 
      ], 
      valueWithMax: [ 
       1,2,3 
      ], 
      valueWithMinMax: [ 
       1,2,3 
      ], 
    ]) 
    testMatchers { 
     // asserts the jsonpath value against manual regex 
     jsonPath('$.duck', byRegex("[0-9]{3}")) 
     // asserts the jsonpath value against the provided value 
     jsonPath('$.duck', byEquality()) 
     // asserts the jsonpath value against some default regex 
     jsonPath('$.alpha', byRegex(onlyAlphaUnicode())) 
     jsonPath('$.alpha', byEquality()) 
     jsonPath('$.number', byRegex(number())) 
     jsonPath('$.aBoolean', byRegex(anyBoolean())) 
     // asserts vs inbuilt time related regex 
     jsonPath('$.date', byDate()) 
     jsonPath('$.dateTime', byTimestamp()) 
     jsonPath('$.time', byTime()) 
     // asserts that the resulting type is the same as in response body 
     jsonPath('$.valueWithTypeMatch', byType()) 
     jsonPath('$.valueWithMin', byType { 
      // results in verification of size of array (min 1) 
      minOccurrence(1) 
     }) 
     jsonPath('$.valueWithMax', byType { 
      // results in verification of size of array (max 3) 
      maxOccurrence(3) 
     }) 
     jsonPath('$.valueWithMinMax', byType { 
      // results in verification of size of array (min 1 & max 3) 
      minOccurrence(1) 
      maxOccurrence(3) 
     }) 
    } 
    headers { 
     contentType(applicationJson()) 
    } 
} 
} 

和例如生成測試(一部分斷言大小)

assertThat((Object) parsedJson.read("$.valueWithMin")).isInstanceOf(java.util.List.class); 
assertThat(parsedJson.read("$.valueWithMin", java.util.Collection.class).size()).isGreaterThanOrEqualTo(1); 
assertThat((Object) parsedJson.read("$.valueWithMax")).isInstanceOf(java.util.List.class); 
assertThat(parsedJson.read("$.valueWithMax", java.util.Collection.class).size()).isLessThanOrEqualTo(3); 
assertThat((Object) parsedJson.read("$.valueWithMinMax")).isInstanceOf(java.util.List.class); 
assertThat(parsedJson.read("$.valueWithMinMax", java.util.Collection.class).size()).isStrictlyBetween(1, 3); 
+0

一個說明,但...如果你挑選的匹配選項,您必須手動如果需要,可以事後匹配整塊 –