Interface Testing & Json Schema

Json is a very widely used data exchange format. From front-end to back-end, from web to app, and heterogeneous languages, the interface becomes a bridge, and Json has become the most widely used data exchange format. During the interface development and testing work, in order to verify the correctness of the interface processing, a large number of tests had to be performed on the Json message format, integrity, and correctness.

1. Introduction to Json Schema

A similar method xmllint has been used to test xml. If you only perform basic checks on the results, you can use the characteristics of weakly typed languages and use Python to deserialize to verify whether the file format is correct. However, if you need to perform logical tests such as type and value range, , via Json Schema is a great fit. Json Schema is a standard that defines Json data constraints. Both the data sender and the receiver can use this agreement to perform data verification to ensure the correctness of the exchanged data.

Advantages of Json Schema:

  • Describe known data formats;
  • Provide documentation that is legible for both humans and machines;
  • Provide help for data verification in the following scenarios;
  • automated test;
  • Ensure the quality of data submitted by users.

The latest Json Schema version is draft 07, released on 2018-03-19, and draft 08 version will be released soon in 2019. Some commonly used features of Json Schema are basically available in the draft 04 version released in 2013, and subsequent versions will improve and enhance some functions. At present, the draft 04 version is the most widely supported Json Schema among various programming languages.

2. Json Schema Example

A, Json

Json is the abbreviation of JavaScript Object Notation and is a simplified data exchange format. As the most common exchange format for data exchange between Internet services, it has the characteristics of simplicity and good readability.

Json mainly has two data structures:

  • object: is an unordered collection of “key/value” pairs. An object starts with “{” and “} ends“. Each key is followed by “:” and key/value pairs are separated by “,“.

  • array: is an ordered collection of values. An array starts with “[Start” and “]End“. Values are separated by “,“.

  • Value can be a string, number, true, false, null, object or array enclosed in double quotes, and the structure can be nested. Most modern computer languages support these data types in some form, making it very convenient to exchange data structures and programming languages through the Json data format.

Json string:

{
    "fruits": [
        "apple",
        "orange",
        "pear"
    ],
    "vegetables": [
        {
            "veggieName": "potato",
            "veggieLike": true,
            "price": 6
        },
        {
            "veggieName": "broccoli",
            "veggieLike": false,
            "price": 8.8
        }
    ]
}

B. Json Schema

The Json Schema document itself is also a multi-level nested Json format data. The writing rules of Json data are defined and constrained through the object data format.

Assume that the above Json string is constrained:

  • Json data is of object type
  • Contains two array type attributes fruits and vegetables
  • The fruits array is of character type
  • The vegetables array is of object type
  • The objects in the vegetables array must contain three attributes: veggieName, veggieLike, and price.
  • The price attribute is a numeric type

Then you can write the following Json Schema for regulatory checking:

{
    "type": "object",
    "properties": {
        "fruits": {
            "type": "array",
            "items": {
                "type": "string"
            }
        },
        "vegetables": {
            "type": "array",
            "items": {
                "type": "object",
                "required": [
                    "veggieName",
                    "veggieLike",
                    "price"
                ],
                "properties": {
                    "price": {
                        "type": "number"
                    }
                }
            }
        }
    }
}
Now I have also found a lot of test friends and created a communication group to share technology, sharing a lot of technical documents and video tutorials we collected.
If you don’t want to experience the feeling of not being able to find resources when studying on your own, having no one to answer your questions, and persisting for a few days before giving up.
You can join us to communicate. And there are many technical experts who have made certain achievements in automation, performance, security, test development, etc.
Share their experience, and also share many live lectures and technical salons
You can learn for free! Focus on it! Open source! ! !
QQ group number: 110685036

3. Json data type

Use the type keyword in Json Schema to agree on data types. Corresponding to Json, the basic data types defined in Json Schema are as follows:

  • string
  • Numeric types (integer, number)
  • object
  • array
  • boolean
  • null

A, string

1. Constraint type

The string type can be constrained through the type keyword, that is, the corresponding data object must be text in the form of a string (unicode characters are supported).

{
    "type": "string"
}

2. Constraint string length

You can also constrain the string length of the data value through minLength and maxLength.

{
    "type": "string",
    "minLength": 2,
    "maxLength": 3
}

As shown in the above constraints, the data “ab” conforms to the agreement, but “abcd” does not.

3. Regular expression support

String constraints support regular expression description, using the pattern keyword.

{
    "type": "string",
    "pattern": "^(\([0-9]{3}\))?[0-9]{3}-[0-9]{4}$"
}

As shown in the above constraints, the string “(086)010-1234” conforms to the agreement, but “(400)13312345678” does not.

4. Format verification

Starting from version 04 of draft, some common fixed formats can also be supported through the built-in format keyword.

1). Time and date format verification

  • date-time supports strings in the format of “2018-11-13T20:20:39 + 00:00”
  • time, supports strings in the format of “20:20:39 + 00:00” (draft 07)
  • date, supports strings in the format of “2018-11-13” (draft 07)

2). Email format verification

3).IP format verification

  • ipv4, verify ipv4 format
  • ipv6, verify ipv6 format

4).Verify URI

  • uri, the verification form is, “https://www.zhihu.com”, URI address

Through the built-in format keyword, format verification of some common character types can be easily completed. Detailed Format can be found in the official documentation.

B. Numeric

The type keyword of the numeric type can take integer and number. Integer can only match integers, while number can match any number (integer or floating point number).

1. Multiple matching

The multipleOf keyword can check whether the data is an integer multiple of the given conditional data.

{
    "type": "number",
    "multipleOf": 10
}

As defined above, data20, 230 conforms to the constraints, but 232 does not.

2. Range matching

Json Schema provides 4 keywords to support verification of numerical value ranges.

| Keywords | Function |
|:------------------ |:------ |
| minimum | value ≥ |
| exclusiveMinimum | value > |
| maximum | value ≤ |
| exclusiveMaximum | value < |

According to the following rules, data 0, 20, 99 conforms to the agreement, but -1, 100 does not.

{
    "type": "number",
    "minimum": 0,
    "exclusiveMaximum": 100
}

C, object

Object is a basic structure of Json, and the constraint data must be an object type.

{
    "type": "object"
}

1. properties keyword

properties is a keyword describing object attribute constraints. Its value must also be an object, and it must also conform to the Json Schema pattern. That is equivalent to taking out the corresponding verification object separately, or you can use the value convention of properties for verification.

{
    "properties": {
        "price": {
            "type": "number"
        }
    }
}

2. propertyNames keyword

The propertyNames keyword is used to constrain property names (key names) and supports regular expressions.

{
    "type": "object",
    "propertyNames": {
        "pattern": "^[A-Za-z_]*$"
    }
}

3. additionalProperties keyword

The additionalProperties keyword is used in conjunction with the properties keyword, and the value can be boolean or object. The function is to restrict the properties defined by properties.

When the value of additionalProperties is boolean false, it means that in addition to the properties defined in properties, no additional properties are allowed.

When it is an object, it also needs to comply with the schema description, which is used to restrict that in addition to the properties defined in properties, additional properties must comply with this keyword constraint.

{
    "type": "object",
    "properties": {
        "number": {
            "type": "number"
        },
        "vegetables": {
            "type": "string"
        },
        "fruits": {
            "type": "string",
            "enum": [
                "pear",
                "watermelon",
                "lemon"
            ]
        }
    },
    "additionalProperties": {
        "type": "string"
    }
}

4. required keyword

The required keyword is also used in conjunction with the properties keyword to agree on the properties that must be included in the properties definition. The value is an array list of property names.

{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "email": {
            "type": "string"
        },
        "address": {
            "type": "string"
        },
        "telephone": {
            "type": "string"
        }
    },
    "required": [
        "name",
        "email"
    ]
}

The above convention indicates that the object data must contain two attributes: name and email, and the other attributes are not required.

5. Keywords that limit the length of the object

minProperties and maxProperties are keywords used to constrain the length of the object object. The value must be a positive integer, and maxProperties should be greater than minProperties.

{
    "type": "object",
    "minProperties": 2,
    "maxProperties": 4
}

The above convention limits the number of corresponding object attributes to at least 2 and no more than 4.

6. Object data dependency keyword

The dependencies keyword defines dependencies between object properties.

{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "credit_card": {
            "type": "number"
        },
        "billing_address": {
            "type": "string"
        }
    },
    "required": [
        "name"
    ],
    "dependencies": {
        "credit_card": [
            "billing_address"
        ]
    }
}

The above constraint means that when the credit_card attribute is present, the billing_address attribute must also be present.

D, array

Array is another basic data structure of Json.

1. items keyword

1). The main keyword to constrain the array type is items, which is used to constrain the value constraints of each item in the array.

{
    "type": "array",
    "items": {
        "type": "number"
    }
}

The above constrains that each value in the array must be an integer.

2) The .items keyword can also be used to agree on the array item by item in the order of the array items.

{
    "type": "array",
    "items": [
        {
            "type": "number"
        },
        {
            "type": "string",
            "enum": [
                "different",
                "same"
            ]
        },
        {
            "type": "object"
        }
    ]
}

The items keyword imposes strict constraints on each item in the array. The following Json satisfies the constraints.

[
    3,
    "different",
    {
        "types": "of values"
    }
]

2. contains keyword (draft 06)

{
    "type": "array",
    "contains": {
        "type": "number"
    }
}

The above constraints will constrain the array to only contain at least one item that meets the conditions.

3. additionalItems keyword

The additionalItems keyword restricts whether the array allows additional array items.

{
    "type": "array",
    "items": [
        {
            "type": "number"
        },
        {
            "type": "string"
        },
        {
            "type": "string",
            "enum": [
                "Street",
                "Avenue",
                "Boulevard"
            ]
        },
        {
            "type": "string",
            "enum": [
                "NW",
                "NE",
                "SW",
                "SE"
            ]
        }
    ],
    "additionalItems": false
}

For the above constraints, the fifth data item is not allowed to appear in the constraint array. But the 3-item array that meets the conditions is consistent with the definition.

4. Array length verification

{
    "type": "array",
    "minItems": 2,
    "maxItems": 3
}

For the above constraints, the length of the array can be defined through minItems and maxItems. The following example defines the array length to be at least 2 and not more than 3.

5. Uniqueness verification

uniqueItems is a keyword that constrains the uniqueness of an array. The value is of boolean type. When it is true, it can constrain each item in the array object to be unique.

{
    "type": "array",
    "uniqueItems": true
}

E, boolean

Boolean constraints are constrained by the type keyword, and the value is true or false.

{
    "type": "boolean"
}

F、null

Null-type constraints are constrained by the type keyword, and the value can only be null.

{
    "type": "null"
}

4. Json Schema common keywords

A. Descriptive keywords

Descriptive keywords do not create actual constraints in Json Schema, but they are very helpful for reading and understanding the relevant constraints in Json Schema. It can be understood as Json Schema’s documentation for Json data.

Descriptive keywords mainly include:

  • title: title describing the object
  • Description: Describe the data
  • default: the default value of the described object
  • example: Keywords supported in draft 06, providing an example of the current constraints
{
    "title": "Match anything",
    "description": "This is a schema that matches anything.",
    "default": "Default value",
    "examples": [
        "Anything",
        4035
    ]
}

B. Enumeration keywords

The enumeration keyword enum is a widely used Json Schema keyword. It is generally used to constrain data to take values within the enumeration range.

{
    "type": "string",
    "enum": [
        "red",
        "amber",
        "green"
    ]
}

C, const constant keyword

The const constant keyword is used to constrain data to a fixed value.

{
    "const": "United States of America"
}

D. Aggregation keywords

The aggregation keyword is a keyword in Json Schema that aggregates multiple constraints.

1. allOf

The data object to be verified meets the requirements only if it satisfies all constraints given in the allOf keyword.

{
    "allOf": [
        {
            "type": "string"
        },
        {
            "maxLength": 5
        }
    ]
}

2. anyOf

The data object to be verified meets the requirements only if it satisfies any of the constraints given in the anyOf keyword.

{
    "anyOf": [
        {
            "type": "string"
        },
        {
            "type": "number"
        }
    ]
}

3. oneOf

The oneOf keyword constrains the data to be verified to exactly match one of the constraints.

{
    "oneOf": [
        {
            "type": "number",
            "multipleOf": 5
        },
        {
            "type": "number",
            "multipleOf": 3
        }
    ]
}

4. not

The not keyword constrains the data to be verified and is not a given constraint.

{
    "not": {
        "type": "string"
    }
}

E. Conditional keywords

Starting from draft 07, the conditional keywords if, then, and else can be supported to give some constrained interdependencies.

{
    "type": "object",
    "properties": {
        "street_address": {
            "type": "string"
        },
        "country": {
            "enum": [
                "United States of America",
                "Canada"
            ]
        }
    },
    "if": {
        "properties": {
            "country": {
                "const": "United States of America"
            }
        }
    },
    "then": {
        "properties": {
            "postal_code": {
                "pattern": "[0-9]{5}(-[0-9]{4})?"
            }
        }
    },
    "else": {
        "properties": {
            "postal_code": {
                "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]"
            }
        }
    }
}

The above constraints constrain the corresponding area code constraints when the country is the United States.

F. Structural keywords

When the amount of Json data is large and there are many similar constraints, structural keywords can be used to organize multiple Json Schema schema files to organize constraints.

The definitions keyword can define constraints that can be referenced.

{
    "definitions": {
        "address": {
            "type": "object",
            "properties": {
                "street_address": {
                    "type": "string"
                },
                "city": {
                    "type": "string"
                },
                "state": {
                    "type": "string"
                }
            },
            "required": [
                "street_address",
                "city",
                "state"
            ]
        }
    }
}

You can reuse some shared constraints by referencing them with the $ref keyword.

{
    "$ref": "#/definitions/address"
}

The $ref keyword can also load references from other schema files.

{
    "$ref": "definitions.json#/address"
}

The $id keyword can specify a unique id for a set of constraints, which facilitates structured references and definition of references and paths.

{
    "$id": "http://foo.bar/schemas/address.json"
}

5. Examples

The following content comes from: http://json-schema.org/learn/getting-started-step-by-step.html

{
  // schema version (OP)
  "$schema": "http://json-schema.org/draft-07/schema#",
  // schema unique identifier (OP)
  "$id": "http://example.com/product.schema.json",
  // schema title (OP)
  "title": "Product",
  // schema description (OP)
  "description": "A product from Acme's catalog",
  //Constraint check object type
  "type": "object",
  //Constrained field description
  "properties": {
    // Constrain productId type to be integer
    "productId": {
      "description": "The unique identifier for a product",
      "type": "integer"
    },
    // Constrain productName type to string
    "productName": {
      "description": "Name of the product",
      "type": "string"
    },
    // Constraint price > 0 (excluding 0)
    "price": {
      "description": "The price of the product",
      "type": "number",
      "exclusiveMinimum": 0
    },
    // Constrain tags to be array type
    "tags": {
      "description": "Tags for the product",
      "type": "array",
      //The item type in the array is string
      "items": {
        "type": "string"
      },
      //The array contains at least 1 item
      "minItems": 1,
      // Each item in the array cannot be reissued
      "uniqueItems": true
    },
    "dimensions": {
      "type": "object",
      // Nested object constraint checking rules
      "properties": {
        "length": {
          "type": "number"
        },
        "width": {
          "type": "number"
        },
        "height": {
          "type": "number"
        }
      },
      //Must contain length, width, height
      "required": [ "length", "width", "height" ]
    }
  },
  // Same as above
  "required": [ "productId", "productName", "price" ]
}

6. Json Schema online editing tool

Defining or writing a Json Schema constraint is still a relatively large and complex task, and it is easy to make some formatting errors during writing. Fortunately, tools can help save a lot of time.

https://www.jsonschema.net/

Through online editing tools, you can easily import Json files, automatically generate Json Schema, and then visually complete some attribute definitions of Json Schema, greatly simplifying the writing workload.

7. Use Json Schema in interface verification

Postman supports a variety of third-party libraries for interface testing script expansion, including a commonly used library tv4 (draft 04 version based on Json Schema) that uses Json Schema for interface verification.

A. Writing MockController

@Slf4j
@RestController
public class MyController
{
    @RequestMapping(value = "/testA", produces = "application/json")
    public String testA(HttpServletRequest request)
    {
        String str = "";
        return str;
    }
    
    @RequestMapping(value = "/testB", produces = "application/json")
    public String testB(HttpServletRequest request)
    {
        String str = "";
        return str;
    }
}

1. JsonA to be tested

{
    "productId": 1,
    "productName": "An ice sculpture",
    "price": 12.5,
    "tags": [
        "cold",
        "ice"
    ],
    "dimensions": {
        "length": 7,
        "width": 12,
        "height": 9.5
    },
    "warehouseLocation": {
        "latitude": -78.75,
        "longitude": 20.4
    }
}

2. JsonB to be tested

{
    "productId": 1,
    "productName": "An ice sculpture",
    "price": "12.50",
    "tags": [
        "cold",
        "ice",
        "ice"
    ],
    "dimensions": {
        "length": 7,
        "height": 9.5
    },
    "warehouseLocation": {
        "latitude": -78.75,
        "longitude": 20.4
    }
}

B. Define Json Schema and tv4 verification

var schema = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "http://example.com/product.schema.json",
    "title": "Product",
    "description": "A product from Acme's catalog",
    "type": "object",
    "properties": {
        "productId": {
            "description": "The unique identifier for a product",
            "type": "integer"
        },
        "productName": {
            "description": "Name of the product",
            "type": "string"
        },
        "price": {
            "description": "The price of the product",
            "type": "number",
            "exclusiveMinimum": 0
        },
        "tags": {
            "description": "Tags for the product",
            "type": "array",
            "items": {
                "type": "string"
            },
            "minItems": 1,
            "uniqueItems": true
        },
        "dimensions": {
            "type": "object",
            "properties": {
                "length": {
                    "type": "number"
                },
                "width": {
                    "type": "number"
                },
                "height": {
                    "type": "number"
                }
            },
            "required": ["length", "width", "height"]
        },
        "warehouseLocation": {
            "required": ["latitude", "longitude"],
            "type": "object",
            "properties": {
                "latitude": {
                    "type": "number",
                    "minimum": -90,
                    "maximum": 90
                },
                "longitude": {
                    "type": "number",
                    "minimum": -180,
                    "maximum": 180
                }
            }
        }
    },
    "required": ["productId", "productName", "price"]
}

//tv4.validateMultiple method can return all mismatches in the current schema

pm.test('Json Schema verification passed', function () {
    var result = tv4.validateMultiple(pm.response.json(), schema);
    console.log(result.errors)
    pm.expect(result.valid).to.be.true
});

C. PostMan executes Tests

1. TestA interface

2. TestA interface

Detailed failure reasons can be seen in the Console.

Mainstream languages provide good support for Json Schema and can be directly integrated for testing.

Finally, I would like to thank everyone who has read my article carefully. Looking at the increase in fans and attention, there is always some courtesy. Although it is not a very valuable thing, if you can use it, you can take it directly!

Software testing interview document

We must study to find a high-paying job. The following interview questions are the latest interview materials from first-tier Internet companies such as Alibaba, Tencent, Byte, etc., and some Byte bosses have given authoritative answers. After finishing this set I believe everyone can find a satisfactory job based on the interview information.