Unit testing 如何为需要引用';静态生存期和实现同步?

Unit testing 如何为需要引用';静态生存期和实现同步?,unit-testing,mocking,rust,type-conversion,Unit Testing,Mocking,Rust,Type Conversion,我曾经测试过我的项目。我不知道say\u hello\u brother需要什么类型的类型转换。简化代码列表如下: lib.rs #![feature(plugin, custom_derive)] #![plugin(mockers_macros)] #[cfg(test)] extern crate mockers; use mockers::Scenario; #[derive(Mock)] trait SayHello { fn hello(&self); } //

我曾经测试过我的项目。我不知道
say\u hello\u brother
需要什么类型的类型转换。简化代码列表如下:

lib.rs

#![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)
}
和错误信息:

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...
error[E0277]:特性绑定'std::rc::rc:std::marker::Sync'在'SayHelloMock'中不满足`
-->src\lib.rs:22:5
|
22 |向兄弟问好(&mock)
|^^^^^^^^^^^^^^^^^^^^^^^^`std::rc::rc`无法在线程之间安全共享
|
=帮助:在“SayHelloMock”中,“std::marker::Sync”特性没有为“std::rc::rc”实现`
=注意:必需,因为它出现在类型“SayHelloMock”中`
更新经过一番尝试,我成功地将
Sync
附加到
SayHelloMock
。新的lib.rs:

#![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)
}
#![功能(插件、自定义_派生)]
#![插件(mockers\u宏)]
#[cfg(测试)]
外部板条箱模拟机;
使用mockers::场景;
你好{
fn你好(&self);
}
嘲弄{
赛赫洛莫克,
自己
你好{
fn你好(&self);
}
}
SayHelloMock{}的不安全impl同步
//假设“SayHello”是一个服务,在多个线程上工作
fn向兄弟问好(兄弟:&'T){
兄弟你好
}
#[测试]
fn test_sya_hello(){
let scenario=scenario::new();
//不行
//让mock=scenario.create_mock::();
//静态MOCK:SayHelloMock=|{MOCK};
//向兄弟问好(&MOCK)
//还不行
让mock:&'static SayHelloMock=&(scenario.create_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...
error[E0597]:借入值的有效期不够长
-->src\lib.rs:38:41
|
38 |让mock:&'static SayHelloMock=&(scenario.create|u mock::());
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^临时值的寿命不够长
39 |向兄弟问好(模拟)
40 | }
|-临时价值仅在此之前有效
|
=注意:借用值必须在静态生存期内有效。。。

这个问题有点模糊,但如果我理解正确,您想知道如何将模拟传递给函数
say\u hello\u brother
。问题在于,该函数需要一个同样实现
Sync
特性的对象。因此,您无法将
mock
转换为其他类型以获得要编译的代码

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

mock! {
    SayHelloMock,
    self,
    trait SayHello {
        // trait methods here
    },
    self,
    trait Sync {
        // trait methods here
    }
}
然后在测试中,您将创建如下模拟:

let mut mock = scenario.create_mock::<SayHelloMock>();
let mut mock=scenario.create_mock::();
您不能将mocker库用于此目的,因为它生成的Mock是无效的

也就是说,没有任何东西限制您创建自己的线程安全模拟:

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);
}

谢谢,我觉得这个方法太简单了,无法测试。在实际测试中,不仅需要调用计数,还需要参数检查,更重要的是每个调用的参数可能不同。但是对我来说,惰性静态是新的,我会尝试it@llxxbb根据您提供的代码,除了调用的总数之外,没有其他东西可以测试。当然,这里的解决方案可以扩展,并且对于几乎无限数量的置换来说是复杂的。你说得对,但我不喜欢用大量的模拟结构来代替一个好的模拟框架。模拟框架可以简化代码结构并易于理解。@llxxbb
#[派生(模拟)]
创建这些结构。你不是在回避它们,只是在把它们打印出来。无论如何,这个答案让您能够向该库提交PR,以使它生成的模拟
发送
同步
。你确定它可以工作吗?我遇到了另一个错误:错误[E0200]:trait
std::marker::Sync
需要一个
unsafe impl
declaration@llxxbb我知道你可以同时模仿两个特征,所以我建议尝试这种方法,我没有用这个具体的例子来尝试。您是否尝试将同步标记为不安全:
不安全的特征同步
?我尝试了,然后再次出错:不安全的特征还不受支持,但我通过添加“SayHelloMock{}的不安全impl Sync”使其工作。但我不能将
静态
生存期添加到模拟中,请参见我附加的问题。