assert_json
A easy and declarative way to test JSON input in Rust. assert_json
is a Rust macro heavily inspired by serde json macro. Instead of creating a JSON value from a JSON literal, assert_json
makes sure the JSON input conforms to the validation rules specified.
assert_json
also output beautiful error message when a validation error occurs.
How to use
use assert_json::assert_json;
use assert_json::validators;
#[test]
fn test_json_ok() {
let json = r#"
{
"status": "success",
"result": {
"id": 5,
"name": "charlesvdv"
}
}
"#;
let name = "charlesvdv";
assert_json!(json, {
"status": "success",
"result": {
"id": validators::u64(|&v| if v > 0 { Ok(())} else { Err(String::from("id should be greater than 0")) }),
"name": name,
}
}
);
}
Any variables or expressions are interpoled as validation rules matching the type and value of the variable/expression passed to the macro.
Now, if JSON input is changed to something incorrect like this:
let json = r#"
{
"status": "success",
"result": {
"id": 5,
- "name": "charlesvdv"
+ "name": "incorrect name"
}
}
"#;
You will get an comprehensible error message like this one:
thread 'xxxx' panicked at 'error: Invalid JSON
┌─ :4:17
│
4 │ "name": "incorrect name"
│ ^^^^^^^^^^^^^^^^ Invalid value. Expected "charlesvdv" but got "incorrect name".
Custom validators
A set of validators are already implemented in the validators
module. If required, one can also creates its own validation routine by implementing the Validator
trait.
use assert_json::{assert_json, Error, Validator, Value};
fn optional_string(expected: Option<String>) -> impl Validator {
OptionalStringValidator { expected }
}
/// Matches a null JSON value if expected is None, else check if the strings
/// are equals
struct OptionalStringValidator {
expected: Option<String>,
}
impl Validator for OptionalStringValidator {
fn validate<'a>(&self, value: &'a Value) -> Result<(), Error<'a>> {
if let Some(expected_str) = &self.expected {
let string_value = value
.as_str()
.ok_or_else(|| Error::InvalidType(value, String::from("string")))?;
if expected_str == string_value {
Ok(())
} else {
Err(Error::InvalidValue(value, expected_str.clone()))
}
} else {
value.as_null()
.ok_or_else(|| Error::InvalidType(value, String::from("null")))
}
}
}
let json = r#"
{
"key": "value",
"none": null
}
"#;
assert_json!(json, {
"key": optional_string(Some(String::from("value"))),
"none": optional_string(None),
});
Alternatives
Acknowledgments
Thanks a lot to the serde-rs/json project members and especially those who contributed to the json!
macro.