接口测试进阶:在接口测试中框架中使用json schema

当今接口测试越来越重要,一般情况下我们总是会对接口的返回的json字符串进行验证,看返回是否跟我们的预期相符。不过很多情况下我们会遇到下面的问题

  • 响应结果在测试中不停的发生变动,比如昨天还是3个字段,今天可能返回值里只有2个字段了,测试这边没有比较好的方式感受到后端的变化
  • 我们需要对json的返回值进行一些校验,需要写很多的断言,大部分时候这些断言都是相似的,或者是重复的,比如说校验某个字段的长度必须小于10之类的

那如何解决呢?

  • 与前后端沟通好返回值的字段,类型以及校验规则,最好有前后端+测试端统一一份合约,大家都按照合约来进行数据的处理
  • 测试的时候通过合约里定义好的校验规则进行数据校验

这时候json schema就派上用场了。

json schema

JSON Schema 是一种 JSON 媒体类型,用于定义 JSON 数据的结构。JSON 模式旨在定义 JSON 数据的验证,可用于验证响应和请求 JSON。在 JSON Schema 中,我们可以验证数据类型、字段是否为必填、最小长度或最大长度等。

举例

下面的数据代表了一个员工的信息

  • id: employeeId
  • 员工名称: employeeName
  • 年龄: employeeAge
  • 职称: jobTitle
  • 爱好: hobby
{
  "employeeId": 1,
  "employeeName": "Fulan",
  "employeeAge": 23,
  "jobTitle": "SDET",
  "hobby": [
    "watch movies",
    "play football"
  ]
}

上面的定义其实是有一些疑问的,比如

  • id是什么意思
  • employeeName的最大长度是多少
  • employeeAge的最小值是什么
  • jobTitle是必填吗
  • hobby可以填几个

我们可以通过生成JSON schema来回答上面的问题

{
    "$schema": "http://json-schema.org/draft-07/schema",
    "$id": "http://example.com/example.json",
    "type": "object",
    "title": "The root schema",
    "description": "The root schema comprises the entire JSON document.",
    "default": {},
    "examples": [
        {
            "employeeId": 1,
            "employeeName": "Fulan",
            "employeeAge": 23,
            "jobTitle": "SDET",
            "hobby": [
                "watch movie",
                "play football"
            ]
        }
    ],
    "required": [
        "employeeId",
        "employeeName",
        "employeeAge",
        "jobTitle",
        "hobby"
    ],
    "properties": {
        "employeeId": {
            "$id": "#/properties/employeeId",
            "type": "integer",
            "title": "The employeeId schema",
            "description": "An explanation about the purpose of this instance.",
            "default": 0,
            "examples": [
                1
            ]
        },
        "employeeName": {
            "$id": "#/properties/employeeName",
            "type": "string",
            "title": "The employeeName schema",
            "description": "An explanation about the purpose of this instance.",
            "default": "",
            "examples": [
                "Fulan"
            ]
        },
        "employeeAge": {
            "$id": "#/properties/employeeAge",
            "type": "integer",
            "title": "The employeeAge schema",
            "description": "An explanation about the purpose of this instance.",
            "default": 0,
            "examples": [
                23
            ]
        },
        "jobTitle": {
            "$id": "#/properties/jobTitle",
            "type": "string",
            "title": "The jobTitle schema",
            "description": "An explanation about the purpose of this instance.",
            "default": "",
            "examples": [
                "SDET"
            ]
        },
        "hobby": {
            "$id": "#/properties/hobby",
            "type": "array",
            "title": "The hobby schema",
            "description": "An explanation about the purpose of this instance.",
            "default": [],
            "examples": [
                [
                    "watch movies",
                    "play football"
                ]
            ],
            "additionalItems": true,
            "items": {
                "$id": "#/properties/hobby/items",
                "anyOf": [
                    {
                        "$id": "#/properties/hobby/items/anyOf/0",
                        "type": "string",
                        "title": "The first anyOf schema",
                        "description": "An explanation about the purpose of this instance.",
                        "default": "",
                        "examples": [
                            "watch movies",
                            "play football"
                        ]
                    }
                ]
            }
        }
    },
    "additionalProperties": true
}

看上去很多很乱对不对,别着急,我们慢慢看

  • $schema 关键字表明此模式是根据标准的特定草案编写的,并且用于各种原因,主要是版本控制。
  • $id 关键字定义模式的 URI 和模式中其他 URI 引用解析的基本 URI。
  • title和description注释关键字只是描述性的。它们不会对正在验证的数据添加约束。使用这两个关键字来说明模式的意图。
  • type 关键字定义了我们的 JSON 数据的第一个约束,在这种情况下,它必须是一个 JSON 对象。

更具体一点

properties里定义了各个字段的详情,我们可以在里面增加更多的约束

{
    "$schema": "http://json-schema.org/draft-07/schema",
    "$id": "http://example.com/example.json",
    "type": "object",
    "title": "The root schema",
    "description": "The root schema comprises the entire JSON document.",
    "default": {},
    "examples": [
        {
            "employeeId": 1,
            "employeeName": "Fulan",
            "employeeAge": 23,
            "jobTitle": "SDET",
            "hobby": [
                "watch movie",
                "play football"
            ]
        }
    ],
    "required": [
        "employeeId",
        "employeeName",
        "employeeAge",
        "jobTitle",
        "hobby"
    ],
    "properties": {
        "employeeId": {
            "$id": "#/properties/employeeId",
            "type": "integer",
            "title": "The employeeId schema",
            "description": "An explanation about the purpose of this instance.",
            "default": 0,
            "examples": [
                1
            ]
        },
        "employeeName": {
            "$id": "#/properties/employeeName",
            "type": "string",
            "title": "The employeeName schema",
            "description": "An explanation about the purpose of this instance.",
            "default": "",
            "examples": [
                "Fulan"
            ]
        },
        "employeeAge": {
            "$id": "#/properties/employeeAge",
            "type": "integer",
            "title": "The employeeAge schema",
            "description": "An explanation about the purpose of this instance.",
            "default": 0,
            "exclusiveMinimum": 20,
            "examples": [
                23
            ]
        },
        "jobTitle": {
            "$id": "#/properties/jobTitle",
            "type": "string",
            "title": "The jobTitle schema",
            "description": "An explanation about the purpose of this instance.",
            "default": "",
            "minLength": 4,
            "examples": [
                "SDET"
            ]
        },
        "hobby": {
            "$id": "#/properties/hobby",
            "type": "array",
            "title": "The hobby schema",
            "description": "An explanation about the purpose of this instance.",
            "default": [],
            "examples": [
                [
                    "watch movies",
                    "play football"
                ]
            ],
            "additionalItems": true,
            "items": {
                "$id": "#/properties/hobby/items",
                "anyOf": [
                    {
                        "$id": "#/properties/hobby/items/anyOf/0",
                        "type": "string",
                        "title": "The first anyOf schema",
                        "description": "An explanation about the purpose of this instance.",
                        "default": "",
                        "examples": [
                            "watch movies",
                            "play football"
                        ]
                    }
                ]
            },
            "uniqueItems": true
        }
    },
    "additionalProperties": true
}

在上面的例子中我们规定

  • employeeId的默认值是0
  • employeeAge最小值是20
  • jobTitle的最小长度是4
  • hobbies必须排重,所以uniqueItems的值是true

json schema合约可以尽可能的详细,这样模糊的点就会相对较少,验证的结果会更加的准确。

在测试框架中使用json schema

这里以java为例,首先我们引入json schema的支持,然后定义断言工具,最后在用例中使用该断言。

引入json schema支持,这里用的是https://github.com/everit-org/json-schema,pom.xml如下



    4.0.0

    org.example
    json-schema
    1.0-SNAPSHOT

    
        8
        8
    
    
        
            org.testng
            testng
            7.4.0
            test
        
        
            org.everit.json
            org.everit.json.schema
            1.3.0
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.12.4
        
        
            io.rest-assured
            rest-assured
            4.3.0
            test
        
    


view raw

定义断言工具函数

package utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import functest.APITest;
import org.everit.json.schema.Schema;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.testng.Assert;

import java.util.logging.Logger;

public class JsonSchemaUtils {

    private static Logger LOGGER= Logger.getLogger(String.valueOf(JsonSchemaUtils.class));

    private ObjectMapper objMapper = new ObjectMapper();

    public void checkJsonSchema(String jsonSchemaPath, String jsonSubject) throws ValidationException {

        JSONObject retVal = new JSONObject();

        try {
            JSONObject jsonSchema = new JSONObject(new JSONTokener(APITest.class.getResourceAsStream(jsonSchemaPath)));
            Schema schema = SchemaLoader.load(jsonSchema);
            schema.validate(objMapper.convertValue(jsonSubject, JSONObject.class));
            retVal.put("errorMessage","");
        } catch (ValidationException ex) {
            ex.printStackTrace();
            LOGGER.info("JSON Schema Error Message: " + ex.getMessage());
            retVal.put("errorMessage",ex.getMessage());
            Assert.assertEquals(retVal.getString("errorMessage"), "");
        }
        Assert.assertEquals(retVal.getString("errorMessage"), "");
    }
}

在用例中使用

package functest;

import io.restassured.RestAssured;
import org.json.JSONObject;
import org.testng.annotations.Test;
import io.restassured.response.Response;
import utils.JsonSchemaUtils;

public class APITest {

    private final static String JSON_SCHEMA_ACTIVITY_PATH = "/schema/apiTest-jsonSchema.response.json";

    JsonSchemaUtils jsonSchemaUtils = new JsonSchemaUtils();

    @Test
    public void getTest() {

        Response response = RestAssured.get("https://www.boredapi.com/api/activity/");
        JSONObject jsonObj = new JSONObject(response.getBody().asString());
        System.out.println(jsonObj.toString(4));
        jsonSchemaUtils.checkJsonSchema(JSON_SCHEMA_ACTIVITY_PATH,response.asString());

    }

}

最后

JSON schema 是一个多功能库,可以帮助我们执行 API 测试,使用 JSON 文件定义 schema 要求的能力显示了这个库的强大功能。希望这些示例能让您了解如何在项目中使用模式验证。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取 【100%免费无套路】 

å¨è¿éæå¥å¾çæè¿°

 全套资料获取方式:点击下方小卡片自行领取即可

你可能感兴趣的:(软件测试,程序员,接口测试,自动化测试,测试工程师)