serde 实现中的模拟实例
Mock instance inside serde implementation
我正在尝试实现使用一些外部功能的自定义反序列化 function/method。该函数创建一个实例并使用它的方法。它工作正常,但我不知道如何在测试中模拟该服务。
更普遍的问题是:如何为反序列化提供状态function/method?
下面的代码说明了我的意思。
MagickBook
是一个外部服务,它保存状态并包含 MagickBook::find
方法中的一些基本逻辑。
Scroll
是一个可反序列化的数据结构,应该使用MagicBook
.
中的逻辑反序列化
我想有一种方法可以在反序列化时从外部提供 MagicBook
的特定实例。例如在测试中。
use serde::de::{Deserialize, Deserializer}; // 1.0.82
use serde_derive::Deserialize; // 1.0.82
use serde_json; // 1.0.33
struct MagickBook;
// Some service which I want to mock in the test
impl MagickBook {
fn new() -> Self {
Self {}
}
fn find(&self, _kind: &str) -> isize {
let effect = 42;
// Here we do some logic depending on input parameter
// -- snip --
return effect;
}
}
#[derive(Deserialize, PartialEq, Debug)]
struct Scroll {
#[serde(rename = "kind")]
#[serde(deserialize_with = "deserialize_effect")]
effect: isize,
}
fn deserialize_effect<'de, D>(deserializer: D) -> Result<isize, D::Error>
where
D: Deserializer<'de>,
{
let book = MagickBook::new();
Ok(book.find(&String::deserialize(deserializer)?))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn main() {
let scroll: Scroll = serde_json::from_str("{\"kind\":\"wind\"}").unwrap();
assert_eq!(scroll, Scroll { effect: 42 });
}
}
我建议通过内部可变线程本地实例访问模拟。
use serde::{Deserialize, Deserializer};
use std::cell::RefCell;
struct MagickBook {
value: isize,
}
thread_local! {
static MAGICK_BOOK: RefCell<MagickBook> = RefCell::new(MagickBook::new());
}
impl MagickBook {
fn new() -> Self {
MagickBook { value: 0 }
}
fn find(&self, _kind: &str) -> isize {
let effect = self.value;
// -- snip --
effect
}
}
#[derive(Deserialize, PartialEq, Debug)]
struct Scroll {
#[serde(rename = "kind", deserialize_with = "deserialize_effect")]
effect: isize,
}
fn deserialize_effect<'de, D>(deserializer: D) -> Result<isize, D::Error>
where
D: Deserializer<'de>,
{
let kind = String::deserialize(deserializer)?;
Ok(MAGICK_BOOK.with(|book| book.borrow().find(&kind)))
}
#[test]
fn test_deserialize() {
MAGICK_BOOK.with(|book| book.borrow_mut().value = 42);
let scroll: Scroll = serde_json::from_str(r#"{"kind":"wind"}"#).unwrap();
assert_eq!(scroll, Scroll { effect: 42 });
}
我正在尝试实现使用一些外部功能的自定义反序列化 function/method。该函数创建一个实例并使用它的方法。它工作正常,但我不知道如何在测试中模拟该服务。
更普遍的问题是:如何为反序列化提供状态function/method?
下面的代码说明了我的意思。
MagickBook
是一个外部服务,它保存状态并包含 MagickBook::find
方法中的一些基本逻辑。
Scroll
是一个可反序列化的数据结构,应该使用MagicBook
.
我想有一种方法可以在反序列化时从外部提供 MagicBook
的特定实例。例如在测试中。
use serde::de::{Deserialize, Deserializer}; // 1.0.82
use serde_derive::Deserialize; // 1.0.82
use serde_json; // 1.0.33
struct MagickBook;
// Some service which I want to mock in the test
impl MagickBook {
fn new() -> Self {
Self {}
}
fn find(&self, _kind: &str) -> isize {
let effect = 42;
// Here we do some logic depending on input parameter
// -- snip --
return effect;
}
}
#[derive(Deserialize, PartialEq, Debug)]
struct Scroll {
#[serde(rename = "kind")]
#[serde(deserialize_with = "deserialize_effect")]
effect: isize,
}
fn deserialize_effect<'de, D>(deserializer: D) -> Result<isize, D::Error>
where
D: Deserializer<'de>,
{
let book = MagickBook::new();
Ok(book.find(&String::deserialize(deserializer)?))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn main() {
let scroll: Scroll = serde_json::from_str("{\"kind\":\"wind\"}").unwrap();
assert_eq!(scroll, Scroll { effect: 42 });
}
}
我建议通过内部可变线程本地实例访问模拟。
use serde::{Deserialize, Deserializer};
use std::cell::RefCell;
struct MagickBook {
value: isize,
}
thread_local! {
static MAGICK_BOOK: RefCell<MagickBook> = RefCell::new(MagickBook::new());
}
impl MagickBook {
fn new() -> Self {
MagickBook { value: 0 }
}
fn find(&self, _kind: &str) -> isize {
let effect = self.value;
// -- snip --
effect
}
}
#[derive(Deserialize, PartialEq, Debug)]
struct Scroll {
#[serde(rename = "kind", deserialize_with = "deserialize_effect")]
effect: isize,
}
fn deserialize_effect<'de, D>(deserializer: D) -> Result<isize, D::Error>
where
D: Deserializer<'de>,
{
let kind = String::deserialize(deserializer)?;
Ok(MAGICK_BOOK.with(|book| book.borrow().find(&kind)))
}
#[test]
fn test_deserialize() {
MAGICK_BOOK.with(|book| book.borrow_mut().value = 42);
let scroll: Scroll = serde_json::from_str(r#"{"kind":"wind"}"#).unwrap();
assert_eq!(scroll, Scroll { effect: 42 });
}