如何为特征提供模拟(没有模拟魔法)

问题描述 投票:0回答:1

说我有两个特质

特质.rs

pub trait MessagingService {
    fn new() -> Self
...
}

pub trait WebService {
    fn create_client() -> Client;
    fn send_request(req: RequestBuilder) -> Option<Value>;
}

还有一个模块,我在其中实现这两个不和谐的特征

服务/discord.rs

pub struct DiscordService {
    client: Client,
}

impl WebService for DiscordService {
// a.k.a the transport layer
   fn send_request(req: RequestBuilder) -> Option<Value> {
       // contains all the code involved that involves actual HTTP requests
   }
}

impl MessagingService for DiscordService {
// contains the code that
// i) build request
// ii) processing of the values returned by WebService::send_request
    fn update_task_status(&self, task: &mut Task) {
       let body = json!({"what":"ever"});
       let _ = Self::send_request(
            self.client
                .post(format!(
                    "{BASE_URL}/channels/{}/messages",
                    CONF.discord_channel
                ))
                .json(&body),
        );
    }
}

我想模拟传输部分,即

WebService
,这样我就可以独立测试
MessagingService
的功能。

我多次读到,正确的 rustacean 方法是 为特征提供模拟,而不是模拟对象。我将其理解为在我的测试中提供了这一特性的新实现。

服务/discord.rs

...
#[cfg(test)]
mod tests {
    use reqwest::blocking::{Client, RequestBuilder};
    use serde_json::Value;
    use super::DiscordService;
    use crate::structs::WebService;

    impl WebService for DiscordService {
        fn send_request(req: RequestBuilder) -> Option<Value>{
            // builds Values from sourced files instead 
            // of sending HTTP requests 
        }
    }
    #[test]
    fn some_test() {
    let notifier: DiscordService = DiscordService::new();
    // test notifier.update_task_status
    }
}

纸面上看起来不错,但我得到了

conflicting implementations of trait WebService for type discord::DiscordService
。我认为
mod tests {}
会像 encapsulation 一样工作,允许我提供
WebService
的替代实现,但事实似乎并非如此。我不想创建像
DiscordServiceMock
这样的新结构,因为它会使我的代码的某些部分无法测试。

有没有一种方法可以提供这样的实现,而不会最终导致冲突?还有别的办法吗?

rust mocking
1个回答
0
投票

不,这不是 Rust 的工作方式或应该使用的方式。正如 Rust Reference 中所述,不允许对一个类型进行多个重叠的实现:

如果孤立规则检查失败或存在重叠的实现实例,则特征实现被认为是不连贯的。

对此有多种解决方案。它们都不是 Rust 特定的。

如果您坚持模拟部分代码的想法,则可以将特征视为接口并使用某种策略模式(其中涉及注入不同的策略)。然后实施测试策略(如

DiscordServiceMock
)并在测试中使用它。

© www.soinside.com 2019 - 2024. All rights reserved.