Skip to content

整体结构响应断言

整体结构响应断言

简介

整体结构的响应断言是指在进行接口测试时,对返回的响应数据的整体结构进行验证的一种测试方法。这种方法通常用于确保服务端返回的响应数据与预期的数据结构完全一致,包括字段名称、字段值以及字段类型等方面。

应用场景

在接口自动化测试过程中,经常会碰到动辄几百个响应字段的场景。碰到这种类型的接口,会碰到两难的选择:

如果不做业务断言,无法保证接口的正确性。

如果做业务断言,工作量非常大,维护也比较困难。

那么针对于“大响应数据”我们可以这样断言:

  • 针对主要且少量的业务字段断言。
  • 其他字段不做数据正确性断言,只做类型与整体结构的校验。
  • 与前面的版本进行 diff,对比差异化的地方。

实现方案

整体结构响应断言的实现方式,就需要应用到 JSONSchema 工具。

JSONSchema 整体结构响应断言

  • 预先生成对应结构的 Schema。
  • 将实际获取到的响应与生成的 Schema 进行对比。

JSONSchema 的生成

通过界面工具生成:

  • 复制 JSON 数据。
  • 粘贴到在线生成工具中。
  • 自动生成 JSON Schema 数据。
  • JSON Schema 在线生成工具:https://app.quicktype.io。

通过第三方库生成:

Python

  • 安装:pip install genson
  • 调用方法生成对应的 JSONSchema 数据结构。
from genson import SchemaBuilder
obj = {
  "greeting": "Welcome to quicktype!",
  "instructions": [
    "Type or paste JSON here",
    "Or choose a sample above",
    "quicktype will generate code in your",
    "chosen language to parse the sample data"
  ]
}
def generate_jsonschema(obj):
    # 实例化jsonschem
    builder = SchemaBuilder()
    # 传入被转换的对象
    builder.add_object(obj)
    # 转换成 schema 数据
    return builder.to_schema()
schema = generate_jsonschema(obj)

# 打印生成的 JSON schema
print(schema)

Java

引入依赖:

<!-- JSON Schema Generator -->
<dependency>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-generator</artifactId>
    <version>4.36.0</version>
</dependency>
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.github.victools.jsonschema.generator.SchemaVersion;
import com.github.victools.jsonschema.generator.OptionPreset;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonSchemaGenerator {

    public static void main(String[] args) {
        // 创建样本 JSON 对象
        Map<String, Object> obj = new HashMap<>();
        obj.put("greeting", "Welcome to quicktype!");
        obj.put("instructions", List.of(
            "Type or paste JSON here",
            "Or choose a sample above",
            "quicktype will generate code in your",
            "chosen language to parse the sample data"
        ));

        // 生成 JSON Schema
        JsonNode schema = generateJsonSchema(obj);

        // 打印生成的 JSON Schema
        System.out.println(schema.toPrettyString());
    }

    public static JsonNode generateJsonSchema(Map<String, Object> obj) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.valueToTree(obj);

        // 配置 Schema 生成器
        SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(mapper, SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON);
        SchemaGeneratorConfig config = configBuilder.build();
        SchemaGenerator generator = new SchemaGenerator(config);

        // 生成 Schema
        return generator.generateSchema(jsonNode.getClass());
    }
}

JSONSchema 验证

Python:

  • 安装:pip install jsonschema
  • 调用 validate() 进行验证。
from jsonschema import validate

# 定义一个简单的 JSON Schema
schema = {
    "type": "object",
    "properties": {
        "greeting": {"type": "string"},
        "instructions": {"type": "array"}
    },
    "required": ["greeting", "instructions"]
}

obj = {
    "greeting": "Welcome to quicktype!",
    "instructions": [
        "Type or paste JSON here",
        "Or choose a sample above",
        "quicktype will generate code in your",
        "chosen language to parse the sample data"
    ]
}

def schema_validate(obj, schema):
    '''
    对比 python 对象与生成的 JSONSchema 的结构是否一致
    '''
    try:
        validate(instance=obj, schema=schema)
        return True
    except Exception as e:
        return False

result = schema_validate(obj, schema)
print(result)

Java:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonSchemaValidation {

    public static void main(String[] args) {
        // 定义一个简单的 JSON Schema
        String schemaStr = "{\n" +
                "  \"type\": \"object\",\n" +
                "  \"properties\": {\n" +
                "    \"greeting\": {\"type\": \"string\"},\n" +
                "    \"instructions\": {\"type\": \"array\"}\n" +
                "  },\n" +
                "  \"required\": [\"greeting\", \"instructions\"]\n" +
                "}";

        // 创建样本 JSON 对象
        Map<String, Object> obj = new HashMap<>();
        obj.put("greeting", "Welcome to quicktype!");
        obj.put("instructions", List.of(
                "Type or paste JSON here",
                "Or choose a sample above",
                "quicktype will generate code in your",
                "chosen language to parse the sample data"
        ));

        // 进行 JSON Schema 验证
        boolean result = schemaValidate(obj, schemaStr);
        System.out.println(result);
    }

    public static boolean schemaValidate(Map<String, Object> obj, String schemaStr) {
        try {
            // 创建 ObjectMapper 实例
            ObjectMapper mapper = new ObjectMapper();

            // 将 Java 对象转换为 JSON 字符串
            String jsonStr = mapper.writeValueAsString(obj);

            // 解析 JSON Schema
            JSONObject jsonSchema = new JSONObject(new JSONTokener(schemaStr));
            Schema schema = SchemaLoader.load(jsonSchema);

            // 解析 JSON 对象
            JSONObject jsonObject = new JSONObject(new JSONTokener(jsonStr));

            // 验证 JSON 对象是否符合 JSON Schema
            schema.validate(jsonObject);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
  • 针对于生成和封装的过程对 JSONSchema 进行二次封装。

Python:

from genson import SchemaBuilder
from jsonschema import validate

class JSONSchemaUtils:
    @classmethod
    def generate_schema(cls, obj):
        builder = SchemaBuilder()
        builder.add_object(obj)
        return builder.to_schema()

    @classmethod
    def schema_validate(cls, obj, schema):
        try:
            validate(instance=obj, schema=schema)
            return True
        except Exception as e:
            return False

# 定义一个 JSON 对象
obj = {
    "greeting": "Welcome to quicktype!",
    "instructions": [
        "Type or paste JSON here",
        "Or choose a sample above",
        "quicktype will generate code in your",
        "chosen language to parse the sample data"
    ]
}

# 生成 JSON schema
schema = JSONSchemaUtils.generate_schema(obj)

# 打印生成的 JSON schema
print(schema)

# 准备要验证的对象
obj_to_validate = {
    "greeting": "Hello, World!",
    "instructions": [
        "Type or paste JSON here",
        "Or choose a sample above"
    ]
}

# 验证对象与生成的 JSON schema 结构一致性
is_valid = JSONSchemaUtils.schema_validate(obj_to_validate, schema)

if is_valid:
    print("Object is valid according to JSON schema.")
else:
    print("Object is not valid according to JSON schema.")

Java:

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.3</version>
    </dependency>
    <dependency>
        <groupId>org.everit.json</groupId>
        <artifactId>org.everit.json.schema</artifactId>
        <version>1.14.2</version>
    </dependency>
</dependencies>
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import com.github.victools.jsonschema.generator.SchemaVersion;
import com.github.victools.jsonschema.generator.OptionPreset;
import org.everit.json.schema.loader.SchemaLoader;
import org.everit.json.schema.ValidationException;
import org.everit.json.schema.Schema;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JSONSchemaUtils {

    public static JsonNode generateSchema(Map<String, Object> obj) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.valueToTree(obj);

        SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(mapper, SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON);
        SchemaGeneratorConfig config = configBuilder.build();
        SchemaGenerator generator = new SchemaGenerator(config);

        return generator.generateSchema(jsonNode.getClass());
    }

    public static boolean schemaValidate(Map<String, Object> obj, JsonNode schemaNode) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            String jsonStr = mapper.writeValueAsString(obj);

            JSONObject jsonSchema = new JSONObject(new JSONTokener(schemaNode.toString()));
            Schema schema = SchemaLoader.load(jsonSchema);

            JSONObject jsonObject = new JSONObject(new JSONTokener(jsonStr));
            schema.validate(jsonObject);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) throws Exception {
        // 定义一个 JSON 对象
        Map<String, Object> obj = new HashMap<>();
        obj.put("greeting", "Welcome to quicktype!");
        obj.put("instructions", List.of(
                "Type or paste JSON here",
                "Or choose a sample above",
                "quicktype will generate code in your",
                "chosen language to parse the sample data"
        ));

        // 生成 JSON schema
        JsonNode schema = JSONSchemaUtils.generateSchema(obj);

        // 打印生成的 JSON schema
        ObjectMapper mapper = new ObjectMapper();
        String schemaStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema);
        System.out.println(schemaStr);

        // 准备要验证的对象
        Map<String, Object> objToValidate = new HashMap<>();
        objToValidate.put("greeting", "Hello, World!");
        objToValidate.put("instructions", List.of(
                "Type or paste JSON here",
                "Or choose a sample above"
        ));

        // 验证对象与生成的 JSON schema 结构一致性
        boolean isValid = JSONSchemaUtils.schemaValidate(objToValidate, schema);

        if (isValid) {
            System.out.println("Object is valid according to JSON schema.");
        } else {
            System.out.println("Object is not valid according to JSON schema.");
        }
    }
}

总结

  • JSONSchema 的生成
  • JSONSchema 验证