测试 serde“with”属性的序列化/反序列化函数

Zia*_*man 5 testing rust serde

Serde 派生宏能够通过字段属性控制字段的序列化/反序列化方式#[serde(with = "module")]。应该"module"具有具有正确参数和返回类型的序列化和反序列化函数。

不幸的是,这个例子有点过于做作

use serde::{Deserialize, Serialize};

#[derive(Debug, Default, PartialEq, Eq)]
pub struct StringPair(String, String);

mod stringpair_serde {
    pub fn serialize<S>(sp: &super::StringPair, ser: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        ser.serialize_str(format!("{}:{}", sp.0, sp.1).as_str())
    }

    pub fn deserialize<'de, D>(d: D) -> Result<super::StringPair, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        d.deserialize_str(Visitor)
    }

    struct Visitor;

    impl<'de> serde::de::Visitor<'de> for Visitor {
        type Value = super::StringPair;

        fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            write!(f, "a pair of strings separated by colon (:)")
        }

        fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(s.split_once(":")
                .map(|tup| super::StringPair(tup.0.to_string(), tup.1.to_string()))
                .unwrap_or(Default::default()))
        }
    }
}

#[derive(Serialize, Deserialize)]
struct UsesStringPair {
    // Other fields ...

    #[serde(with = "stringpair_serde")]
    pub stringpair: StringPair,
}

fn main() {
    let usp = UsesStringPair {
        stringpair: StringPair("foo".to_string(), "bar".to_string()),
    };

    assert_eq!(
        serde_json::json!(&usp).to_string(),
        r#"{"stringpair":"foo:bar"}"#
    );

    let usp: UsesStringPair = serde_json::from_str(r#"{"stringpair":"baz:qux"}"#).unwrap();

    assert_eq!(
        usp.stringpair,
        StringPair("baz".to_string(), "qux".to_string())
    )
}
Run Code Online (Sandbox Code Playgroud)

使用简单的断言来测试派生序列化UsesStringPair是微不足道的。但我看过serde_test例子,因为这对我来说也有意义。

但是,我希望能够独立测试这些stringpair_serde::{serialize, deserialize}功能(例如,如果我的板条箱仅提供mycrate::StringPairmycrate::stringpair_serde,并且UsesStringPair供板条箱用户实现)。

我研究的一种方法是创建一个serde_json::Serializer(使用new, 需要一个io::Write实现,我无法弄清楚如何简单地创建和使用它,但这是一个单独的问题)并使用创建的序列化器调用序列化,然后对结果和以前一样。然而,这并没有测试 的任何/所有实现serde::Serializer,只是测试 中提供的实现serde_json

我想知道是否有像serde_test示例中那样的方法适用于模块提供的 ser/deser 函数。

And*_*sen 1

其中没有方法serde_test可以直接测试这些功能。虽然在内部serde_test使用它自己的Serializer类型Deserializer,但它不会公开这些类型,因此您不能在测试中直接使用它们。

但是,您可以使用serde_assert板条箱来完成此操作(免责声明:我写的serde_assert)。serde_assert直接公开它SerializerDeserializer专门用于测试,并且非常适合您的用例:

use serde_assert::{Deserializer, Serializer, Token, Tokens};

#[test]
fn serialize() {
    let serializer = Serializer::builder().build();

    assert_eq!(
        stringpair_serde::serialize(
            &StringPair("foo".to_string(), "bar".to_string()),
            &serializer
        ),
        Ok(Tokens(vec![Token::Str("foo:bar".to_string())])),
    );
}

#[test]
fn deserialize() {
    let mut deserializer = Deserializer::builder()
        .tokens(Tokens(vec![Token::Str("foo:bar".to_string())]))
        .build();

    assert_eq!(
        stringpair_serde::deserialize(&mut deserializer),
        Ok(StringPair("foo".to_string(), "bar".to_string()))
    );
}
Run Code Online (Sandbox Code Playgroud)