Hamcrest with MockMvc: Check if key exists, but value may be null


nebula

I'm using MockMvc to do some tests and I want to validate the structure of the JSON response. Specifically, I want to make sure that the property key exists and the value is of some type or null.

{
   "keyToNull": null,  # This may be null, or a String
   "keyToString": "some value"
}

The following works for me, but I'm wondering if there's a way to combine each combination of the two expectations into one line, since I'm checking a lot of properties:

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.hamcrest.Matchers.*;

.andExpect(jsonPath("$").value(hasKey("keyToNull")))
.andExpect(jsonPath("$.keyToNull").value(
                  anyOf(any(String.class), nullValue(String.class))))

.andExpect(jsonPath("$").value(hasKey("keyToString")))
.andExpect(jsonPath("$.keyToString").value(
                  anyOf(any(String.class), nullValue(String.class))))

hasKey()This has to be done because another declaration itself passes when a non-existing keymap in MockMvc's implementation is null:

.andExpect(jsonPath("$.notAKey").value(
                  anyOf(any(String.class), nullValue(String.class)))) // ok

jsonPath().exists()doesn't work either, because internally it compares the value with null.

I thought about making a separate method like this:

private static <T> void assertNullableAttr(ResultActions res, String jsonPath, Class<T> type) throws Exception {
    int split = jsonPath.lastIndexOf('.');
    String prefix = jsonPath.substring(0, split), key = jsonPath.substring(split+1);

    res.andExpect(jsonPath(prefix).value(hasKey(key)))
        .andExpect(jsonPath(jsonPath).value(anyOf(any(type), nullValue(type))));
    }

However, this forces me to split the code in an unnatural way:

ResultActions res = mockMvc.perform(get("/api"))
    // these attributes must not be null
    .andExpect(jsonPath("$.someInfo").value(hasSize(2)))
        .andExpect(jsonPath("$.someInfo[0].info1").value(any(String.class)))
        .andExpect(jsonPath("$.someInfo[0].info2").value(any(String.class)))
    .andExpect(jsonPath("$.addlInfo").value(hasSize(2)))
        .andExpect(jsonPath("$.addlInfo[0].info1").value(any(String.class)))
        .andExpect(jsonPath("$.addlInfo[0].info2").value(any(String.class)));

// these attributes may be null
assertNullableAttr(res, "$.someInfo[0].info3", String.class);
assertNullableAttr(res, "$.someInfo[0].info4", String.class);

assertNullableAttr(res, "$.addlInfo[0].info3", String.class);
assertNullableAttr(res, "$.addlInfo[0].info4", String.class);

Is it possible to apply a clever Hamcrest Matcher to a single json path per property?

Yonatan:

You can add the following static matcher factories:

public static <K> Matcher<Map<? extends K, ?>> hasNullKey(K key) {
    return new IsMapContaining<K,Object>(equalTo(key), anyOf(nullValue(), anyString());
}

Then you can use it like this:

// will succeed, because keyToNull exists and null
.andExpect(jsonPath("$").value(hasNullKey("keyToNull")))

// will succeed, bacause keyToString exists and not null
.andExpect(jsonPath("$").value(hasNullKey("keyToString")))

// will fail, because notAKey doesn't exists
.andExpect(jsonPath("$").value(hasNullKey("notAKey")))

Related


Hamcrest check if value is null or empty array

Nikolai Golub : I have a code that returns JSON where one of the fields may be null or an empty array. I have the following code to check: import static org.hamcrest.core.AnyOf.anyOf; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcres

Check if a key or value exists in a dictionary

sooh99 First of all, thanks for your help in advance. I'm coding for the book Autocomplete boring stuff with Python and am currently new to learning Python and have a conceptual question about multiple assignments. https://automatetheboringstuff.com/chapter5/

Check if a key or value exists in a dictionary

sooh99 First of all, thanks for your help in advance. I'm coding for the book Autocomplete boring stuff with Python and am currently new to learning Python and have a conceptual question about multiple assignments. https://automatetheboringstuff.com/chapter5/

NSIS - Check if registry key value exists

username I need to check if a registry value exists. How can I do this? My first method: ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports" "NUL:" ${IF} $0 == "" MESSAGEBOX MB_OK "NUL exists" ${ELSE}

Check if value exists as key in dictionary via NSDate

photosynthesis I have a dictionary like this: var dic = [NSDate: Int]() Using this in my iOS to-do app to get the number of tasks completed on a specific date. I only care about the year, month and day parts in the NSDate, and also want to be able to use this

How to check if a key/value pair exists in php?

Damon I'm getting a list of schools for each athlete. I only want to show that school if the athlete's status is . Otherwise, I want to return all properties.committed: true Here is my data: ... "offers": [ { "school": "Foo School", "commit

NSIS - Check if registry key value exists

username I need to check if a registry value exists. How can I do this? My first method: ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports" "NUL:" ${IF} $0 == "" MESSAGEBOX MB_OK "NUL exists" ${ELSE}

How to check if key or value exists in Pyspark Map

W05aDePQw6h8e7 I have a Map column in spark DF and want to filter this column on a specific key (ie keep the row if the key in the map matches the desired value). For example, my schema is defined as: df_schema = StructType( [StructField('id', StringType()),

Check if the key exists in the map, then update the value

December In my project I want to insert keypoints to the map. All new keys should have a value of 1.0, but existing keys should have a value of 1. this is the code vector <string> pairs; map<string, float> two; map <string, float>::iterator it; string a = "a

Check if key exists in array and replace its value

Dragon Bear Customer code I am using the client 's id to be sent from the client var socket = io.connect('http://localhost:8080?token='+userID); and get it on the server using the io.on('connection') function server code let token = socket.handshake.query.tok

Check if a key/value pair exists in an array

Nicholas John I need to check if a set of query parameters exists in a larger set of query parameters. For example, I want to check if , array('option' => 'com_pages', 'view' => 'page')exists in: Array ( [option] => com_pages [format] => html [view

Check if key/value pair exists in another object

zinc zinc If I have the following two objects (object A and object B), how can I check if the key/value of object B exists for object A? In the example below, it should return True because both "make: "Apple" and 'Model: "iPad" exist in object A. Edit: Object

Check if value exists as key in dictionary via NSDate

photosynthesis I have a dictionary like this: var dic = [NSDate: Int]() Using this in my iOS to-do app to get the number of tasks completed on a specific date. I only care about the year, month and day parts in the NSDate, and also want to be able to use this

Check if key exists in Presto value map

the_darkside I'm new to Presto and can't quite figure out how to check if a key exists in the map. When I run SELECTthe query, this error message is returned: Key not present in map: element SELECT value_map['element'] FROM mytable WHERE name = 'foobar' add A

Check if substring key exists in word and return value

Jiejie I'm trying to find the most time efficient way to categorize expenses on accounting software. The value is like this: "EFTPOS Kathmandu 2342342" I created a method as follows: private static string Classifier(string inputDescription) {

NSIS - Check if registry key value exists

username I need to check if a registry value exists. How can I do this? My first method: ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Ports" "NUL:" ${IF} $0 == "" MESSAGEBOX MB_OK "NUL exists" ${ELSE}