代码之家  ›  专栏  ›  技术社区  ›  llxxbb

如何为需要引用“静态生存期”并实现同步的函数提供模拟值?

  •  1
  • llxxbb  · 技术社区  · 7 年前

    我用过 mocker 来测试我的项目。我不知道需要什么类型的类型转换 say_hello_brother . 简化代码列表如下:

    lib。卢比

    #![feature(plugin, custom_derive)]
    #![plugin(mockers_macros)]
    #[cfg(test)]
    extern crate mockers;
    
    use mockers::Scenario;
    
    #[derive(Mock)]
    trait SayHello {
        fn hello(&self);
    }
    
    // assume `SayHello` is a service and  worked on multiple threads
    fn say_hello_brother<T: SayHello + Sync>(brother: &'static T) {
        brother.hello()
    }
    
    #[test]
    fn test_sya_hello() {
        let scenario = Scenario::new();
        let mock = scenario.create_mock_for::<SayHello>();
        say_hello_brother(&mock)
    }
    

    货物汤姆

    [package]
    name = "mock"
    version = "0.1.0"
    authors = ["llxxb"]
    
    [dependencies]
    mockers = "0.9.4"
    mockers_macros = "0.9.4"
    

    和错误信息:

    error[E0277]: the trait bound `std::rc::Rc<std::cell::RefCell<mockers::ScenarioInternals>>: std::marker::Sync` is not satisfied in `SayHelloMock`
      --> src\lib.rs:22:5
       |
    22 |     say_hello_brother(&mock)
       |     ^^^^^^^^^^^^^^^^^ `std::rc::Rc<std::cell::RefCell<mockers::ScenarioInternals>>` cannot be shared between threads safely
       |
       = help: within `SayHelloMock`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc<std::cell::RefCell<mockers::ScenarioInternals>>`
       = note: required because it appears within the type `SayHelloMock`
    

    更新 经过一番尝试,我成功地 Sync SayHelloMock . 新库。卢比:

    #![feature(plugin, custom_derive)]
    #![plugin(mockers_macros)]
    #[cfg(test)]
    extern crate mockers;
    
    use mockers::Scenario;
    
    trait SayHello {
        fn hello(&self);
    }
    
    
    mock! {
        SayHelloMock,
        self,
        trait SayHello {
            fn hello(&self);
        }
    }
    
    unsafe impl Sync for SayHelloMock {}
    
    
    // assume `SayHello` is a service and  worked on multiple threads
    fn say_hello_brother<T: SayHello + Sync>(brother: &'static T) {
        brother.hello()
    }
    
    #[test]
    fn test_sya_hello() {
        let scenario = Scenario::new();
    // not work
    //    let mock = scenario.create_mock::<SayHelloMock>();
    //    static MOCK: SayHelloMock = || { mock };
    //    say_hello_brother(&MOCK)
    
        // not work yet
        let mock : &'static SayHelloMock = &(scenario.create_mock::<SayHelloMock>());
        say_hello_brother(mock)
    }
    

    但我仍然无法将其转换为“静态错误信息:

    error[E0597]: borrowed value does not live long enough
    --> src\lib.rs:38:41
    |
    38 |     let mock : &'static SayHelloMock = &(scenario.create_mock::<SayHelloMock>());
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
    39 |     say_hello_brother(mock)
    40 | }
    | - temporary value only lives until here
    |
    = note: borrowed value must be valid for the static lifetime...
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Shepmaster Tim Diekmann    7 年前

    不能 为此,请使用mocker库,因为它生成的Mock是 not thread safe .

    也就是说,没有什么限制您创建自己的线程安全模拟:

    use std::sync::atomic::{AtomicUsize, Ordering};
    
    #[derive(Debug, Default)]
    struct MyMock {
        call_count: AtomicUsize,
    }
    
    impl SayHello for MyMock {
        fn hello(&self) {
            self.call_count.fetch_add(1, Ordering::SeqCst);
        }
    }
    

    但是,您的签名需要 &'static T ,这可能真的是个糟糕的主意。您需要使用类似惰性静态的东西:

    #[macro_use]
    extern crate lazy_static;
    
    #[test]
    fn test_say_hello() {
        lazy_static! { 
            static ref MOCK: MyMock = MyMock::default();
        };
        say_hello_brother(&*MOCK);
        assert_eq!(MOCK.call_count.load(Ordering::SeqCst), 1);
    }
    
        2
  •  1
  •   Shepmaster Tim Diekmann    7 年前

    这个问题有点模糊,但如果我理解正确,您想知道如何将模拟传递给函数 say_hello_brother . 问题是该函数需要一个实现 Sync 还有特质。因此,您无法转换 mock 以获取要编译的代码。

    根据 documentation of mocker ,你可以试着同时模仿两个特征。下面是一些伪代码,说明了这一想法:

    mock! {
        SayHelloMock,
        self,
        trait SayHello {
            // trait methods here
        },
        self,
        trait Sync {
            // trait methods here
        }
    }
    

    然后在测试中,您将创建如下模拟:

    let mut mock = scenario.create_mock::<SayHelloMock>();