nrxus / faux

Struct mocking library for Rust
https://nrxus.github.io/faux/
MIT License
411 stars 14 forks source link

Partial mocks #56

Closed jbuckmccready closed 9 months ago

jbuckmccready commented 9 months ago

I poked around a little bit but couldn't find a way to partially mock a struct. E.g., struct with 2 methods method1 and method2, I want to mock method1 and use the real implementation for method2, is there a way to do that?

nrxus commented 9 months ago

There isn't a built-in way to do partial mocks in faux. I've always found them to be an anti-pattern and I think this article explains it better than I could: https://github.com/testdouble/contributing-tests/wiki/Partial-Mock

That being said, I know that sometimes the are necessary evils when dealing with legacy code (meaning adding tests to code that is not tested and thus not factored in a testable way) so I played around a bit and saw that it is doable just a little awkward (but I think the awkwardness here is good because partial mocks are not encouraged and hence should not be easy to use IMO).

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

    #[test]
    fn partial() {
        // Make a mock instance
        let mut mock = Foo::faux();
        // Make a real instance
        let real = Foo::new(2, 3);
        // mock the function you want to be mocked
        faux::when!(mock.to_be_mocked()).then_return(999);
        // defer to the real instance for the other function.
        // `then()` requires the closure to be static so we need to `move` real
        // We could use `then_unchecked()` for more complex cases
        faux::when!(mock.to_be_real()).then(move |_| real.to_be_real());

        assert_eq!(mock.to_be_mocked(), 999);
        assert_eq!(mock.to_be_real(), 3);
    }
}

This approach means that you have to manually specify every method that wants to defer to the real method which may be verbose depending on your situation but again I want to emphasize that partial mocks are generally an anti-pattern and a smell that there is something that needs to be improved in the code and tests so I'd recommend not using partial mocks.

For the full code of this example: https://github.com/nrxus/faux-playground/blob/2086fa5cc266f9b9f0de5d43e72fa2c56600c4a4/src/partial_mocks.rs.

jbuckmccready commented 9 months ago

Makes sense, thanks for the example.

I don't currently have a use case for this, I am investigating possible limitations I may stumble into in the future.