1

On using Python3.6 unittest assertRaisesRegex to validate some JSON there are differences in the output generated between validating code under the JSON oneOf keyword and code that is not. I am testing the removal of required properties.

The problem is that the user expects one type of error message but another is received and assertRaisesRegex fails as it does not match the regex.

Using http://json-schema-validator.herokuapp.com to validate the JSON I see the actual error message expected has been nested deeper.

I can get around the problem by searching for the new message when testing for oneOf properties, but want to know if there is a better way to handle this problem that is consistent with my other tests, i.e. using the same format for the messages I expect?

Below are some examples of output that test for required JSON properties being removed. The expected message format is marked with a => the unexpected with **

Example 1 (herokuapp.com): When a required property is removed (not under oneOf)

[ {
  "level" : "error",
  "schema" : {
    "loadingURI" : "#",
    "pointer" : "/properties/Attr_B"
  },
  "instance" : {
    "pointer" : "/Attr_B"
  },
  "domain" : "validation",
  "keyword" : "required",
=>"message" : "object has missing required properties ([\"alpha\"])",
  "required" : [ "alpha", "beta" ],
  "missing" : [ "alpha" ]
} ]

Example 2 (herokuapp.com): When a oneOf nested required property is removed

[ {
  "level" : "error",
  "schema" : {
    "loadingURI" : "#",
    "pointer" : "/properties/Attr_B/properties/beta"
  },
  "instance" : {
    "pointer" : "/Attr_B/beta"
  },
  "domain" : "validation",
  "keyword" : "oneOf",
**"message" : "instance failed to match exactly one schema (matched 0 out of 1)",
  "matched" : 0,
  "nrSchemas" : 1,
  "reports" : {
    "/properties/Attr_B/properties/beta/oneOf/0" : [ {
      "level" : "error",
      "schema" : {
        "loadingURI" : "#",
        "pointer" : "/properties/Attr_B/properties/beta/oneOf/0"
      },
      "instance" : {
        "pointer" : "/Attr_B/beta"
      },
      "domain" : "validation",
      "keyword" : "required",
=>    "message" : "object has missing required properties ([\"min_percentage\"])",
      "required" : [ "max_percentage", "min_percentage" ],
      "missing" : [ "min_percentage" ]
    } ]
  }
} ]

Within my unittests using jsonschema, the messages differ but the problem is the same.

Example 1 (jsonschema): When a required property is removed (not under oneOf)

E
======================================================================
ERROR: test_valid__JSON_against_schema (__main__.SchemaTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 42, in test_valid__JSON_against_schema
    validate(test_json, test_schema)
  File "/local_scratch/tools/PACKAGES/Python-3.6.1/lib/python3.6/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/local_scratch/tools/PACKAGES/Python-3.6.1/lib/python3.6/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
=>  jsonschema.exceptions.ValidationError: 'alpha' is a required property

Failed validating 'required' in schema['properties']['Attr_B']:
    {'additionalProperties': False,
     'properties': {'alpha': {'enum': ['a', 'b'], 'type': 'string'},
                    'beta': {'oneOf': [{'additionalProperties': False,
                                        'properties': {'max_percentage': {'additionalProperties': False,
                                                                          'maximum': 150,
                                                                          'minimum': 10,
                                                                          'type': 'integer'},
                                                       'min_percentage': {'additionalProperties': False,
                                                                          'maximum': 50,
                                                                          'minimum': 1,
                                                                          'type': 'integer'}},
                                        'required': ['min_percentage',
                                                     'max_percentage'],
                                        'type': 'object'}]}},
     'required': ['alpha', 'beta'],
     'type': 'object'}

On instance['Attr_B']:
    {'beta': {'max_percentage': 24, 'min_percentage': 24}}

----------------------------------------------------------------------
Ran 1 test in 0.004s

FAILED (errors=1)

Example 2 (jsonschema): When a oneOf nested required property is removed

E
======================================================================
ERROR: test_valid__JSON_against_schema (__main__.SchemaTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 42, in test_valid__JSON_against_schema
    validate(test_json, test_schema)
  File "/local_scratch/tools/PACKAGES/Python-3.6.1/lib/python3.6/site-packages/jsonschema/validators.py", line 541, in validate
    cls(schema, *args, **kwargs).validate(instance)
  File "/local_scratch/tools/PACKAGES/Python-3.6.1/lib/python3.6/site-packages/jsonschema/validators.py", line 130, in validate
    raise error
**  jsonschema.exceptions.ValidationError: {'max_percentage': 24} is not valid under any of the given schemas

Failed validating 'oneOf' in schema['properties']['Attr_B']['properties']['beta']:
    {'oneOf': [{'additionalProperties': False,
                'properties': {'max_percentage': {'additionalProperties': False,
                                                  'maximum': 150,
                                                  'minimum': 10,
                                                  'type': 'integer'},
                               'min_percentage': {'additionalProperties': False,
                                                  'maximum': 50,
                                                  'minimum': 1,
                                                  'type': 'integer'}},
                'required': ['min_percentage', 'max_percentage'],
                'type': 'object'}]}

On instance['Attr_B']['beta']:
    {'max_percentage': 24}

----------------------------------------------------------------------
Ran 1 test in 0.005s

FAILED (errors=1)

I am validating against this schema

{
    "id": "a-schema",
    "$schema": "http://json-schema.org/draft-04/schema#",
    "description": "my schema",

    "type": "object",
    "properties": {

        "Attr_A": {

            "type": "integer",
            "minimum" : 1,
            "maximum" : 200,
            "additionalProperties": false            
        },

        "Attr_B": {

            "type": "object",
            "properties": {

                "alpha": {

                    "type": "string",
                    "enum": ["a", "b"]
                },

                "beta": {

                    "oneOf": [
                        {
                            "type": "object",
                            "properties": {

                                "min_percentage": {

                                    "type": "integer",
                                    "minimum" : 1,
                                    "maximum" : 50,
                                    "additionalProperties": false
                                },

                                "max_percentage": {

                                    "type": "integer",
                                    "minimum" : 10,
                                    "maximum" : 150,
                                    "additionalProperties": false
                                }
                            },

                            "additionalProperties": false,
                            "required": ["min_percentage", "max_percentage"]
                        }
                    ]
                }
            },

            "additionalProperties": false,
            "required": ["alpha", "beta"]
        },

        "Attr_C": {

            "type": "object",
            "properties": {

                "min_percentage": {

                    "type": "integer",
                    "minimum" : 1,
                    "maximum" : 50,
                    "additionalProperties": false
                },

                "max_percentage": {

                    "type": "integer",
                    "minimum": 10,
                    "maximum": 150,
                    "additionalProperties": false
                }
            },

            "additionalProperties": false,
            "required": ["min_percentage", "max_percentage"]
        }
    },

    "additionalProperties": false,
    "required": ["Attr_A", "Attr_B", "Attr_C"]
}

Here is my instance data

{
    "Attr_A": 123,

    "Attr_B": {

        "alpha": "a",

        "beta": {

             "min_percentage": 20,
             "max_percentage": 24
        }
    },

    "Attr_C": {

         "min_percentage": 20,
         "max_percentage": 24    
    }
}

These are my tests

with open("schema.json") as schema_file:
    test_schema = json.load(schema_file)
schema_file.close()

with open("test.json") as json_file:
    test_json = json.load(json_file)
json_file.close()

### Test the whole JSON is valid against the Schema
def test_valid__JSON_against_schema(self):
    global test_schema
    global test_json
    validate(test_json, test_schema)

### 'Attr_B.alpha' test
def test_missing__Attr_B_alpha(self):
    global test_schema
    global test_json
    dict_copy = copy.deepcopy(test_json)
    dict_copy.pop("alpha")
    msg = "'alpha' is a required property"
    with self.assertRaisesRegex(ValidationError, msg):        
        validate(dict_copy, test_schema)

### 'Attr_B.beta.min_percentage' test
def test_missing__Attr_B_beta_min_percentage(self):
    global test_schema
    global test_json
    dict_copy = copy.deepcopy(test_json)
    test_info = dict_copy["Attr_B"]
    beta= test_info["beta"]
    beta.pop("min_percentage")
    msg = "'min_percentage' is a required property"
    with self.assertRaisesRegex(ValidationError, msg):        
        validate(dict_copy, test_schema)
Dodomac
  • 194
  • 2
  • 17

0 Answers0