asomers / mockall

A powerful mock object library for Rust
Apache License 2.0
1.5k stars 62 forks source link

`mismatched types` with `mockall_double` #426

Closed Houndie closed 1 year ago

Houndie commented 1 year ago

Question on how to use mockall_double for struct swapping. I'm new to rust so there may be an obvious solution I'm seeing here, but how to fix this problem is not clear to me!

I've adapted the struct swapping example in the documentation into an actual program:

mod thing {
    pub struct Thing{}

    #[cfg_attr(test,mockall::automock)]
    impl Thing {
        pub fn foo(&self) -> u32 {
            0
        }
    }
}

mod a {
    use mockall_double::double;
    #[double]
    use crate::thing::Thing;

    pub fn do_stuff(thing: &Thing) -> u32 {
        thing.foo()
    }

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

        #[test]
        fn test_foo() {
            let mut mock = Thing::default();
            mock.expect_foo().returning(|| 42);
            do_stuff(&mock);
        }
    }
}

fn main() {
    use a::do_stuff;
    use thing::Thing;

    let t = Thing{};
    println!("{}", do_stuff(&t));
}

When building this code, everything works as expected. However, when running cargo test I get the following error:

error[E0308]: mismatched types
  --> src/main.rs:39:29
   |
39 |     println!("{}", do_stuff(&t));
   |                    -------- ^^ expected struct `MockThing`, found struct `thing::Thing`
   |                    |
   |                    arguments to this function are incorrect
   |
   = note: expected reference `&MockThing`
              found reference `&thing::Thing`
note: function defined here
  --> src/main.rs:17:12
   |
17 |     pub fn do_stuff(thing: &Thing) -> u32 {
   |            ^^^^^^^^ -------------

For more information about this error, try `rustc --explain E0308`.

It's pretty obvious what is happening, mockall_double is struct swapping as expected, however, the main function is still passing a the non-mock to the function, which causes an error.

My question is....is there a way around this while still using struct swapping? I like the idea behind it for testing but this is kind of a blocker

asomers commented 1 year ago

Easy. You need to use #[double] in main() as well as in mod a. Or, just use it at the top level in main.rs, and use super::Thing in mod a.

Houndie commented 1 year ago

Okay! I thought it might be something like that. Not necessarily a fan of the solutions, but it's good to know how it's supposed to be done. I might just mock out with traits instead. Thanks!