如何为Option<String>创建Serde反序列化器以测试自定义函数?
问题:测试处理
Option<String>的serde自定义反序列化函数 我有两个用于serde deserialize_with的自定义函数:
// Converts string to u32 pub fn de_u32_from_str<'de, D>(deserializer: D) -> Result<u32, D::Error> where D: Deserializer<'de>, { let s = String::deserialize(deserializer)?; s.parse::<u32>().map_err(de::Error::custom) } // Converts string that may be `null` to either `Some(u32)` or `None` pub fn de_opt_u32_from_opt_str<'de, D>(deserializer: D) -> Result<Option<u32>, D::Error> where D: Deserializer<'de>, { let s = Option::<String>::deserialize(deserializer)?; s.map(|s| s.parse::<u32>().map_err(de::Error::custom)) .transpose() }
我已通过以下方式测试de_u32_from_str:
fn deserialize_u32_from_str(string: &str, expected: u32) { let de: StrDeserializer<ValueError> = string.into_deserializer(); let result = de_u32_from_str(de).unwrap(); assert_eq!(result, expected); }
但在测试de_opt_u32_from_opt_str时,我无法创建合适的反序列化器:
fn deserialize_opt_u32_from_opt_str(maybe_string: Option<&str>, expected: Option<u32>) { // I need a `deserializer` here let de: ... = ...; let result = de_opt_u32_from_opt_str(de).unwrap(); assert_eq!(result, expected); }
请问如何创建类似let de: StrDeserializer<ValueError> = string.into_deserializer();的反序列化器,但该反序列化器可承载Option<String>,以满足let s = Option::<String>::deserialize(deserializer)?;的需求?
解决方案
方法1:直接利用Option<&str>的IntoDeserializer实现
Option<T>本身实现了IntoDeserializer trait(只要T实现了该trait),所以你可以直接将Option<&str>转换成符合要求的反序列化器:
use serde::de::{Deserializer, IntoDeserializer}; use serde::Deserialize; use serde::de::value::ValueError; fn deserialize_opt_u32_from_opt_str(maybe_string: Option<&str>, expected: Option<u32>) { let de = maybe_string.into_deserializer(); let result = de_opt_u32_from_opt_str(de).unwrap(); assert_eq!(result, expected); }
这个方式能直接覆盖两种场景:当输入是Some("123")时,反序列化器会解析为Some(String);当输入是None时,反序列化器会解析为None。
方法2:用serde_json模拟真实JSON场景
如果需要贴近实际的JSON反序列化逻辑(比如明确处理null值),可以用serde_json::Value构建反序列化器:
use serde_json::Value; use serde::de::Deserializer; fn deserialize_opt_u32_from_opt_str(maybe_string: Option<&str>, expected: Option<u32>) { let json_value = match maybe_string { Some(s) => Value::String(s.to_string()), None => Value::Null, }; let de = json_value.into_deserializer(); let result = de_opt_u32_from_opt_str(de).unwrap(); assert_eq!(result, expected); }
这种方式更符合真实业务中JSON数据的解析场景,能准确模拟null和字符串两种输入情况。
完整测试用例示例
可以编写测试覆盖所有分支:
#[test] fn test_opt_u32_from_opt_str() { // 测试有效字符串转Some(u32) deserialize_opt_u32_from_opt_str(Some("456"), Some(456)); // 测试None转None deserialize_opt_u32_from_opt_str(None, None); // 测试无效字符串的错误分支 let de = Some("not_a_number").into_deserializer(); assert!(de_opt_u32_from_opt_str(de).is_err()); }
内容的提问来源于stack exchange,提问作者Slava.In
相关产品推荐
相关产品推荐

