Rust proptest如何根据Schema生成符合规范的JSON对象策略
基于proptest生成符合OpenAPI Schema的嵌套JSON
需求
- 基于Rust proptest库生成遵循OpenAPI Schema约束的JSON,不生成无约束随机JSON
- JSON对象的键为Schema预定义的固定值,无需随机生成,仅递归调用对应策略生成键对应的值
- 最终返回策略类型为
BoxedStrategy<serde_json::Value>,支持对象任意层级嵌套 - 已完成原始类型策略实现,仅对象生成逻辑存在问题
原有错误原因
之前的实现直接将值生成策略插入serde_json::Map,而非策略运行后生成的JSON值,导致类型不匹配:
fn generate_json_object(object: &ObjectType) -> BoxedStrategy<serde_json::Value> { let mut json_object = serde_json::Map::with_capacity(object.properties.len()); for (name, schema) in &object.properties { let schema_kind = &schema.to_item_ref().schema_kind; // 错误:此处插入的是BoxedStrategy类型,不是serde_json::Value json_object.insert(name.clone(), schema_kind_to_json(schema_kind)); } Just(serde_json::Value::Object(json_object)).boxed() }
尝试的hash_map+固定键Just、prop_filter_map方案均无法优雅支持嵌套组合。
正确实现
核心逻辑:先为每个固定键匹配对应的值生成策略,将所有属性策略组合为列表策略,最终映射组装为serde_json::Value::Object,无需使用HashMapStrategy。
use proptest::prelude::*; use proptest::collection; use serde_json::{Value, Map}; fn generate_json_object(object: &ObjectType) -> BoxedStrategy<Value> { // 收集每个属性对应的(键, 值)生成策略 let mut prop_strategies = Vec::with_capacity(object.properties.len()); for (prop_name, schema) in &object.properties { let schema_kind = &schema.to_item_ref().schema_kind; let value_strat = schema_kind_to_json(schema_kind); // 固定键用Just包装,和值策略组合为单个键值对的生成策略 prop_strategies.push( (Just(prop_name.clone()), value_strat) .prop_map(|(key, val)| (key, val)) ); } // 组合所有属性策略,生成固定长度的键值对列表 let all_props_strat = collection::vec(prop_strategies, object.properties.len()); // 将键值对列表组装为serde_json对象,包装为目标类型 all_props_strat .prop_map(|pairs| { let mut map = Map::with_capacity(pairs.len()); for (k, v) in pairs { map.insert(k, v); } Value::Object(map) }) .boxed() }
实现说明
- 固定键场景不需要使用
hash_map策略:直接用Just持有预定义键名,和对应值策略配对即可,省去键生成、过滤的冗余逻辑 - 天然支持嵌套:如果属性对应Schema为对象类型,
schema_kind_to_json会递归调用当前函数返回嵌套对象策略,proptest自动处理策略嵌套 - 类型匹配:所有策略最终生成的都是
serde_json::Value类型,不存在将策略本身当作值插入的类型错误 - 扩展支持可选属性:只需对非必填属性的值策略用
prop::option::of包装,最终在prop_map阶段过滤掉值为None的键值对即可适配OpenAPI的required约束。
内容的提问来源于stack exchange,提问作者matusf
相关产品推荐
相关产品推荐

