CodeSandwich / Mocktopus

Mocking framework for Rust
MIT License
233 stars 20 forks source link

Mock traits #35

Open asomers opened 5 years ago

asomers commented 5 years ago

Mocktopus is very handy for mocking free functions. But when mocking structs, it requires a real copy of the struct to be instantiated. That's not always easy or possible in test environments. That's why most mocking libraries work in terms of traits instead. It would be great if Mocktopus could provide a macro that would instantiate a trait and mock all of its methods. Something like this:

#[mockable]
pub trait A {
    fn foo(&self) -> u32;
}
mock!{AMock, A}

The mock macro could expand to this:

#[derive(Default)]
pub struct AMock {}
#[mockable]
impl AMock {
    fn foo(&self) -> u32 {
        unimplemented!()
    }
}
CodeSandwich commented 5 years ago

That's an interesting feature to add in the future. For now what about existing mocking tools? Do they miss anything?

asomers commented 5 years ago

No existing mock object library does everything. This is the best comparison of them. https://asomers.github.io/mock_shootout/

BTW, I'm working on a library of my own, but I haven't released it yet.

CodeSandwich commented 5 years ago

That's very interesting, great job with bring it all together and thank you for including Mocktopus!

To be honest I was trying to create a tool for mocking traits too but found obstacles and didn't put enough time into it.

I've dropped idea of building a mock struct based on trait definition passed to a macro very quickly, because it causes a difficult problem when trait inherits from other trait. The mock struct should implement it as well, because it won't compile, but macro has no idea how to do it.

I was trying to construct a fake trait object with https://doc.rust-lang.org/std/raw/struct.TraitObject.html. I think that this approach could give just right amount of power. Unfortunately I couldn't find a way to match fn pointers and trait methods. It's even harder because Rust optimizes away multiple functions delegating to each other and sometimes the same fn pointer shows up in vtable multiple times.