[매주 1라이브러리] - Mockall의 강력한 Rust 대상 시뮬레이션 라이브러리(4부분-완결)

5485 단어
편집자는 윈난에 가서 일주일 동안 미친 듯이 놀다가 자신의 책임과 가치를 잠시 잊어버려서 매주 창고를 제때에 갱신하지 못했습니다. 죄송합니다!
이번이 Mockall 시리즈의 마지막 편이다.

연관 유형


연관 유형을 포함하는 피쳐도 시뮬레이션할 수 있습니다.일반 피쳐와 달리 시뮬레이션된 구조는 일반 구조가 아니므로 시뮬레이션 구조를 정의할 때 연관된 유형을 지정해야 합니다#[automock\]. 속성의 메타 항목을 통해 다음 작업을 수행할 수 있습니다.
#[automock(type Key=u16; type Value=i32;)]
pub trait A {
    type Key;
    type Value;
    fn foo(&self, k: Self::Key) -> Self::Value;
}

let mut mock = MockA::new();
mock.expect_foo()
    .returning(|x: u16| i32::from(x));
assert_eq!(4, mock.foo(4));


다중 피쳐 및 상속 피쳐


여러 피쳐를 구현할 수 있는 아날로그 구조를 생성할 때 상속이 있든 없든 mock! 매크로를 사용해야 합니다.그러나 만들어진 후에 시뮬레이션 대상의 사용 방법은 다름없다.
pub trait A {
    fn foo(&self);
}

pub trait B: A {
    fn bar(&self);
}

mock! {
    //  
    C {}
    // C  
    trait A {
        fn foo(&self);
    }
    // C 
    trait B: A {
        fn bar(&self);
    }
}
let mut mock = MockC::new();
mock.expect_foo().returning(|| ());
mock.expect_bar().returning(|| ());
mock.foo();
mock.bar();


외부 피쳐


Mockall은 당신이 제어하지 않은 외부 패키지에서 정의한 특징과 구조형을 모의할 수 있지만, mock! 매크로가 아니라 #[automock\]를 사용해야 합니다.이렇게 외부 피쳐를 시뮬레이션할 수 있습니다.
mock! {
    MyStruct {}     //  ,   "Mock"  
    trait Clone {   //  
        fn clone(&self) -> Self;
    }
}

let mut mock1 = MockMyStruct::new();
let mock2 = MockMyStruct::new();
mock1.expect_clone()
    .return_once(move || mock2);
let cloned = mock1.clone();


정적 방법


Mockall은 정적 방법을 시뮬레이션할 수도 있지만 주의해야 할 것은정적 방법을 시뮬레이션할 때 기대는 전역적입니다. 여러 테스트에서 정적 방법을 사용하려면 동기화를 제공해야 합니다. 일반적인 방법에서는 기대를 시뮬레이션 대상 위에 설정합니다. 그러나 정적 방법에 대응하는 시뮬레이션 대상이 없기 때문에 '언어 환경' 대상을 만들어서 기대를 설정해야 합니다.
#[automock]
pub trait A {
    fn foo() -> u32;
}

let ctx = MockA::foo_context();
ctx.expect().returning(|| 99);
assert_eq!(99, MockA::foo());


하나의 상용 모델은 구조 방법으로 하나의 특징을 모의하는 것이다.이런 상황에서 너는 구조 방법을 이용하여 시뮬레이션 대상을 되돌릴 수 있다.
struct Foo{}
#[automock]
impl Foo {
    fn from_i32(x: i32) -> Self {
        // ...
    }
    fn foo(&self) -> i32 {
        // ...
    }
}

let ctx = MockFoo::from_i32_context();
ctx.expect()
    .returning(|x| {
        let mut mock = MockFoo::default();
        mock.expect_foo()
            .return_const(x);
        mock
    });
let foo = MockFoo::from_i32(42);
assert_eq!(42, foo.foo());


공통 정적 방법


통용되는 구조형이나 특징적인 정적 방법을 모의할 때 방법 자체가 통용되든 안 되든 틈이 없이 운행할 수 있다.
#[automock]
trait Foo {
    fn new(t: T) -> MockFoo;
}

let ctx = MockFoo::::new_context();
ctx.expect()
    .returning(|_| MockFoo::default());
let mock = MockFoo::::new(42u32);


어경 검사점


언어 환경의 대상이 작용역을 떠날 때 모든 기대는 비워집니다.언어 환경 대상은 다른 시뮬레이션 대상과 마찬가지로 checkpoint 방법이 있다.
#[automock]
pub trait A {
    fn foo() -> u32;
}

let ctx = MockA::foo_context();
ctx.expect()
    .times(1)
    .returning(|| 99);
ctx.checkpoint();   // Panics!


시뮬레이션 대상의 검사점 방법은 정적 방법에 대해 검사를 진행하지 않는다.이 동작은 여러 시뮬레이션 객체를 동시에 사용하는 데 유용합니다. 예를 들면 다음과 같습니다.
#[automock]
pub trait A {
    fn build() -> Self;
    fn bar(&self) -> i32;
}

let ctx = MockA::build_context();
ctx.expect()
    .times(2)
    .returning(|| MockA::default());
let mut mock0 = MockA::build();
mock0.expect_bar().return_const(4);
mock0.bar();
mock0.checkpoint();     //  build checkpoint
let mock1 = MockA::build();


또 하나 주의해야 할 것은 Mockall은 일반적인 상황에서 모든 아날로그 구조형에 매개 변수가 없는 new 방법을 만들 것이다.그러나 new 라는 방법이 포함된 구조형을 시뮬레이션할 때, Mockall은 자동으로 만들어지지 않습니다.

외부 방정식


Mockall은 외부 방정식을 시뮬레이션할 수도 있습니다.정적 방법과 마찬가지로 외부 방정식을 모의할 때의 기대는 전역적이다.아날로그 구조형과 유사하게 아날로그 방정식을 접근할 수 있도록 가져오기에 대한 특별한 디버깅이 필요합니다.관련 유형과 마찬가지로 #[automock\] 속성에 추가 정보를 제공하여 외부 방정식을 시뮬레이션해야만 정상적으로 사용할 수 있다.
mod ffi {
    use mockall::automock;
    #[automock(mod mock;)]
    extern "C" {
        pub fn foo(x: u32) -> i64;
    }
}

cfg_if! {
    if #[cfg(test)] {
        use self::ffi::mock::foo;
    } else {
        use self::ffi::foo;
    }
}

fn do_stuff() -> i64 {
    unsafe{ foo(42) }
}

#[cfg(test)]
mod t {
    use super::*;

    #[test]
    fn test_foo() {
        let ctx = ffi::mock::foo_context();
        ctx.expect()
            .returning(|x| i64::from(x + 1));
        assert_eq!(43, do_stuff());
    }
}


모듈


외부 방정식을 시뮬레이션할 수 있는 것 이외에 Mockall은 모든 Rust 방정식의 모듈에 시뮬레이션을 파생시킬 수 있습니다. 이 기능은 매일 구축 기능을 사용해야 하고 가방에서 사용해야 합니다. feature(proc_macro_hygiene)사용 방법은 외부 기능을 시뮬레이션하는 것과 같지만 시뮬레이션 모듈의 명칭은 자동으로 생성된다.
#![feature(proc_macro_hygiene)]
mod outer {
    use mockall::automock;
    #[automock()]
    pub(super) mod inner {
        pub fn bar(x: u32) -> i64 {
            // ...
        }
    }
}

cfg_if! {
    if #[cfg(test)] {
        use outer::mock_inner as inner;
    } else {
        use outer::inner;
    }
}

#[cfg(test)]
mod t {
    use super::*;

    #[test]
    fn test_foo_bar() {
        let ctx = inner::bar_context();
        ctx.expect()
            .returning(|x| i64::from(x + 1));
        assert_eq!(5, inner::bar(4));
    }
}

좋은 웹페이지 즐겨찾기