12
返回列表 发新帖
楼主: AlexQin

[转载] Cucumber 高阶用法

[复制链接]
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
11#
 楼主| 发表于 2017-1-17 09:55 | 只看该作者
何时初始化 DI 容器
既然 DI 容器中包含了测试用例运行所需要的各种要素,那么何时初始化各种资源是至关重要的。在解释容器初始化之前,本文为您推荐一个较为实用的测试用例组织结构:如 图 2 所示:
图 2. 推荐的测试用例组织结构图


  • resources/features:定义各种功能 specifications;
  • resources/schemas:定义 JSON Schema validation 相关文件;
  • steps:feature 文件对应的 Java Steps;
  • helpers:用于定义测试用例所共用的工具类、方法等;
  • cases:测试用例入口点。

之所以采用这样的组织结构在于能够:
  • 能够清晰的组织测试用例;
  • 对于同一类 artifact,通过命名规范,能够快速定位;
  • 统一的测试入口点便于设置 Cucumber options,对于用例开发过程中的 debug、error analysis 有统一的起点。

那么 DI 容器应该在什么时候初始化呢?
首先,使用 helpers 初始化 DI 容器肯定是不合适的,因为 helper 类和方法自身不能够描述场景,他们只是场景中的一个部分;
其次,如果采用 steps 类来初始化 DI 容器,会造成一个问题:对于有多个 steps 类的情况,会造成 DI 容器初始化多次!
最后,也是最合适的地方:cases package 下的测试用例入口点,其中使用了@ContextConfiguration("classpath:cucumber.xml")出使初始化了 DI 容器。 清单11 为 DI 容器初始化的一个样例:
清单 11. DI 容器初始化
  1. package io.cucumber.samples.dw.cases;
  2. import cucumber.api.CucumberOptions;
  3. import cucumber.api.junit.Cucumber;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.test.context.ContextConfiguration;

  6. /**
  7. * Created by stlv for developerworks article
  8. */
  9. @RunWith(Cucumber.class)
  10. @CucumberOptions(
  11.         format = {
  12.             "pretty",
  13.             "html:target/html-report/",
  14.             "json:target/json-report/dw.json"
  15.         },
  16.         features = {
  17.             "classpath:features"
  18.         },
  19.         glue = {
  20.             "io.cucumber.samples.dw.steps"
  21.         },
  22.         tags = {
  23.             "@api",
  24.             "~@ui"
  25.        }
  26. )
  27. @ContextConfiguration("classpath:cucumber.xml")
  28. public class AppStarterTest {

  29. }
复制代码

对于 CucumberOptions,请参考Cucumber 使用进阶文章中的介绍,此处不再赘述。

覆盖 CucumberOptions 默认值
为什么要 override 已经定义好的 CucumberOptions?最常见的情况可能是这样的:
  • 有一个(些)测试用例失败了,在不改变任何文件的前提下,通过 override CucumberOptions 就能重新运行失败的测试用例,这个是实际场景中最常见的情况;
  • 对于不同的测试环境,可以通过 override CucumberOptions 来实现在不同的环境下运行不同的测试用例。

因此,能够掌握 override CucumberOptions,对于熟练掌握 Cucumber 是非常有益处的。Override CucumberOptions 的常用方法有如下两种:
  • 通过 override Java 系统属性 cucumber.options 来实现。
    • 将 cucumber.options 直接传递给 Java 命令,例如:
      java -Dcucumber.options="-g step_definitions features" cucumber.api.cli.Main
    • 将 cucumber.options 传递给 Maven 命令,例如:
      mvn test -Dcucumber.options="-g step_definitions features"

  • 通过定义环境变量 CUCUMBER_OPTIONS 来实现:
    export CUCUMBER_OPTIONS="-g step_definitions features"

以上两种方式的效果是等价的,读者可以依据实际情况采用不同的实现方式。
截止到这里,读者应该已经能够成功搭建出基于 Spring DI 容器的自动化用例测试工程了,能够以 Live documentation 方式来做测试。
但是,对于本文中待测的 Open API,它返回的是 JSON 数据,因此,并不建议读者止步于此,建议读者继续阅读下文,了解 Rest-Assured 工具,将其集成到测试环境,以便实现 JSON Schema 验证。


使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
12#
 楼主| 发表于 2017-1-17 10:00 | 只看该作者
集成 Rest-Assured 和 JSON Schema 验证
JSON Schema 是一个非常强大的 JSON 结构验证工具,它通过定义 JSON 的结构、数据取值范围等方式验证 JSON 数据。


常用类型
JSON Schema 将 JSON 数据类型划分为 6 种类型:
  • string:文本类型,可以包含 Unicode 字符;
  • number/integer:数字型或整数型;
  • object:类似于 Java 中 map 的概念,包含 key 机器对应的 value,key 在 JSON 中对应与 properties,因此 object 在 JSON 中对应的是包含零个或多个的 properties 的复杂结构;
  • array:对应于数组或 Java 中 list 的概念。
  • boolean:布尔数据类型。
  • null:null 通常用来表示一个不存在的值,当 Schema 中定义某一个 property 是 null,那么这个 property 的取值只有一个:null。

另外,加之 JSON Schema 也支持"引用"的概念,实现 Schema 定义的复用,因此,使用上述常用类型通过各种组合,就可以定义出各种复杂的数据类型。


定义 Schema 验证 Card 这一数据模型
本文所述的 Open API 的返回值也是 JSON 数据,样例如下 snippet 所示。从中可以看出,返回的 JSON 数据最外层是一个通用的结构,用于表示本次 API 调用结果;然后,"data"property 是 API 调用所返回的业务数据。在本例中,它是一个卡片信息描述数据,包括了"id","cardNum"等诸多 properties。同时,还包含了一个"cardBillingAddressList"用于标识持卡人的账单地址信息列表。
清单 12. Card data response
  1. {
  2.     "errName": null,
  3.     "errMsg": "SUCCESS",
  4.     "errCode": 0,
  5.     "data": [
  6.         {
  7.             "id": 1,
  8.             "cardNum": "C0000001",
  9.             "cardOwnerName": "CENT LUI",
  10.             "cardType": "0",
  11.             "cardSeqNum": 0,
  12.             "starPoints": 1024,
  13.             "cardBillingAddressList": [
  14.                 {
  15.                     "id": 1,
  16.                     "cardNum": "C0000001",
  17.                     "region": "AP",
  18.                     "country": "CN",
  19.                     "state": "HeNan",
  20.                     "city": "LuoYang",
  21.                     "street": "Peking Rd",
  22.                     "extDetail": "Apartment 1-13-01 No.777"
  23.                 },
  24.                 {
  25.                     "id": 7,
  26.                     "cardNum": "C0000001",
  27.                     "region": "EU",
  28.                     "country": "ES",
  29.                     "state": "Madrid",
  30.                     "city": "Sol",
  31.                     "street": "Century Rd",
  32.                     "extDetail": "Apartment 1-13-01 No.777"
  33.                 }
  34.             ],
  35.             "primaryCard": true
  36.         }
  37.     ]
  38. }
复制代码

对于这样的返回值,根据上面所述的 JSON Schema 知识,定义出的 Schema 信息如下:
清单 13. Card data JSON Schema
  1. {
  2.   "$schema": "http://json-schema.org/draft-04/schema#",
  3.   "title": "银行卡数据格式验证 Schema",
  4.   "definitions": {
  5.     "eleInnerData": {
  6.       "properties": {
  7.         "id": {
  8.           "type": "integer",
  9.           "minimum": 1
  10.         },
  11.         "cardNum": {
  12.           "$ref":"common-schema.json#/definitions/cardNum"
  13.         },
  14.         "cardOwnerName": {
  15.           "type": "string",
  16.           "minLength": 2,
  17.           "maxLength": 128
  18.         },
  19.         "cardType": {
  20.           "type": "string",
  21.           "minLength": 1,
  22.           "maxLength": 1,
  23.           "enum": [
  24.             "0",
  25.             "1"
  26.           ]
  27.         },
  28.         "cardSeqNum": {
  29.           "type": "integer",
  30.           "minimum": 0,
  31.           "maximum": 127
  32.         },
  33.         "starPoints": {
  34.           "type": "number",
  35.           "minimum": 0.00
  36.         },
  37.         "cardBillingAddressList": {
  38.           "$ref": "address-schema.json"
  39.         },
  40.         "primaryCard": {
  41.           "type": "boolean",
  42.           "enum": [
  43.             true,
  44.             false
  45.           ]
  46.         }
  47.       },
  48.       "required": [
  49.         "id",
  50.         "cardNum",
  51.         "cardOwnerName",
  52.         "cardType",
  53.         "cardSeqNum",
  54.         "starPoints",
  55.         "cardBillingAddressList",
  56.         "primaryCard"
  57.       ],
  58.       "additionalProperties": false
  59.     },
  60.     "eleData": {
  61.       "type": "array",
  62.       "items": {
  63.         "$ref": "#/definitions/eleInnerData"
  64.       },
  65.       "minItems": 0
  66.     }
  67.   },
  68.   "allOf": [
  69.     {
  70.       "$ref": "common-schema.json"
  71.     },
  72.     {
  73.       "type": "object",
  74.       "properties": {
  75.         "data": {
  76.           "$ref": "#/definitions/eleData"
  77.         }
  78.       },
  79.       "required": [
  80.         "data"
  81.       ],
  82.       "additionalProperties": true
  83.     }
  84.   ]
  85. }
复制代码

其中引用了 common-schema 的定义如下:
清单 14. common-schema 定义
  1. {
  2.   "$schema": "http://json-schema.org/draft-04/schema#",
  3.   "title": "通用交互数据格式验证 Schema",
  4.   "definitions": {
  5.     "cardNum": {
  6.       "type": "string",
  7.       "minLength": 8,
  8.       "maxLength": 8,
  9.       "pattern": "[C|S](0*)\\d+"
  10.     },
  11.     "errName": {
  12.       "anyOf": [
  13.         {
  14.           "type": "string",
  15.           "minLength": 1
  16.         },
  17.         {
  18.           "type": "null"
  19.         }
  20.       ]
  21.     },
  22.     "errMsg": {
  23.       "type": "string",
  24.       "minLength": 1
  25.     },
  26.     "errCode": {
  27.       "type": "integer",
  28.       "maximum": 0
  29.     }
  30.   },
  31.   "type": "object",
  32.   "properties": {
  33.     "errName": {
  34.       "$ref": "#/definitions/errName"
  35.     },
  36.     "errMsg": {
  37.       "$ref": "#/definitions/errMsg"
  38.     },
  39.     "errCode": {
  40.       "$ref": "#/definitions/errCode"
  41.     }
  42.   },
  43.   "required": ["errName","errMsg","errCode"],
  44.   "additionalProperties": true
  45. }
复制代码

本文对于 JSON Schema 的定义并未详细描述,读者可以参考Understanding JSON Schema学习如何定义一个有效的 JSON Schema。

在 Rest-Assured 中对返回数据执行 JSON Schema Validation
Rest-Assured 从 version 2.10 开始支持 JSON Schema Validation,读者只需要在 pom 文件中添加如下的 dependency 就可以支持 JSON Schema Validation 了:
清单 15. JSON Schema Validation 所需的 Maven dependencies
  1. <dependency>
  2.     <groupId>com.jayway.restassured</groupId>
  3.     <artifactId>json-schema-validator</artifactId>
  4.     <version>2.9.0</version>
  5.     <scope>test</scope>
  6. </dependency>
复制代码

使用 Rest-Assured 提供的 Schema Validator 验证 Rest-Assured Response 返回数据是非常简单的,下面这个例子中,只是一行代码就能实现以 schemaFile 所指定的 JSON Schema 来验证 response 的 body。
清单 16. 使用 Rest-Assured 做 JSON Schema Validation
  1. public void assertThatRepliedCardDataMetSchemaDefinedSpecs(String schemaFile) {
  2.     response.body(JsonSchemaValidator.
  3.         matchesJsonSchemaInClasspath("schemas/" + schemaFile));
  4. }
复制代码






使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
13#
 楼主| 发表于 2017-1-17 10:02 | 只看该作者
小结
本文首先介绍了服务端开放 API 的交互参数和返回格式,进而介绍如何使用 Cucumber 结合开源的 Rest-Assured 来测试开放 API。本文介绍了如何使用 JSON Schema 来做数据结构和数据有效性验证,从而保证即使在复杂、大量返回数据的情况下也能够轻松地验证数据结构是否符合期望。

参考资源(resources)

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
14#
 楼主| 发表于 2017-1-17 10:03 | 只看该作者

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
15#
 楼主| 发表于 2017-1-21 22:23 | 只看该作者
good job

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
16#
 楼主| 发表于 2017-1-28 17:34 | 只看该作者
新年快乐

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表