How to do self defined serde deserialize function unit tests?

I have some self defined deserialize functions, how to test them? the serde_test crate does not provide function unit tests.

fn deserialize_string_to_size<'de, D>(deserializer: D) -> std::result::Result<u64, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    let (size_num, unit) = parse_string_to_num_and_unit(&s)?;
    match unit {
        "kb" => Ok(size_num * KB),
        "mb" => Ok(size_num * MB),
        "gb" => Ok(size_num * GB),
        "tb" => Ok(size_num * TB),
        "pb" => Ok(size_num * PB),
        _ => Err(de::Error::missing_field("size")),
    }
}

fn parse_string_to_num_and_unit<E: de::Error>(s: &str) -> std::result::Result<(u64, &str), E> {
    if !s.starts_with(char::is_numeric) {
        return Err(E::custom("missing number in configuration"));
    }

    let (h, u) = s.split_at(
        s.chars()
            .position(|x| x.is_alphabetic())
            .ok_or_else(|| E::custom("expecting unit in configuration"))?,
    );
    Ok((
        h.parse()
            .map_err(|e| E::custom(format!("parsing number error: {}", e)))?,
        u,
    ))
}

How can I test these 2 fns?

Maybe create a newtype that wraps a string and use #[serde(with = ...)] to make it use your functions, then use the normal testing facilities on this type.

How about writing tests like this?

#[cfg(test)]
mod tests {
    use serde::Deserialize;
    
    use super::deserialize_string_to_size;
    use super::KB;
    
    #[derive(Deserialize, Debug)]
    struct Example(#[serde(deserialize_with = "deserialize_string_to_size")] u64);
    
    #[test]
    fn size1() {
        let json = r#""12kb""#;
        
        let e: Example = serde_json::from_str(json).unwrap();
        
        assert_eq!(e.0, 12 * KB)
    }
}

Playground.

1 Like

Hi thanks for your advice, I find a way to test it

 #[test]
    fn test_deserialize_string_to_size() {
        assert_eq!(
            10 * KB,
            deserialize_string_to_size(toml::Value::String("10kb".into())).unwrap()
        );
        assert_eq!(
            10 * MB,
            deserialize_string_to_size(toml::Value::String("10mb".into())).unwrap()
        );
        assert_eq!(
            10 * GB,
            deserialize_string_to_size(toml::Value::String("10gb".into())).unwrap()
        );
        assert_eq!(
            10 * TB,
            deserialize_string_to_size(toml::Value::String("10tb".into())).unwrap()
        );
        assert!(deserialize_string_to_size(toml::Value::String("kb".into())).is_err());
        assert!(deserialize_string_to_size(toml::Value::String("10".into())).is_err());
    }