nrxus / faux

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

Mocks without closures #3

Closed nrxus closed 3 years ago

nrxus commented 4 years ago

Currently this library forces the user to always specify a closure for the mock, however oftentimes I just want to always return the same value, or potentially only mock the method for a specific constant parameter which wouldn't need a closure ideally.

Something like:

when!(my_mock.some_method).with_args(3).then_return(5)

Instead of

when!(my_mock.some_method).then_safe(|input| {
    if input != 3 {
        panic!("mock received unexpected input")
    }
    5
}
nrxus commented 4 years ago

Closures in rust feel pretty lightweight to reason about so perhaps this is not as needed as it is in Java's mockito.

However, there might be a way to avoid exposing When::then's unsafe to the user if they have no control over the closures being created for the mock which would be nice :thinking:

nrxus commented 4 years ago

Problem

What is the most intuitive behavior on how this would handle mocks with different arguments.

when!(my_mock.some_method).with_args(3).then_return(666)
when!(my_mock.some_method).with_args(3).then_return(3)
when!(my_mock.some_method).then_safe(|_| 999)
when!(my_mock.some_method).with_args(5).then_return(5)

Options:

Latest Always Wins

my_mock.some_method(3) => panic!. Latest mock does not match the argument my_mock.some_method(10) => panic!. Latest mock does not match the argument my_mock.some_method(5) => 5. Latest mock matches the argument

Latest to handle the argument

my_mock.some_method(3) => 999. Latest mock that handles the input is the closure. my_mock.some_method(10) => 999. Latest mock that handles the input is the closure. my_mock.some_method(5) => 5. Latest mock that handles the input is the specific mock.

Most "specific" that match the argument, then latest.

my_mock.some_method(3) => 3. Most specific mocks return 3 and 666, with 3 being the latest mock. my_mock.some_method(10) => 999. Only mock that handles the argument. my_mock.some_method(5) => 5. Most specific mock.

Trade-offs

These three have different trade offs in most seemingly "correct" vs complexity of both implementation and explanations (i.e., what does "specific" even mean?)

nrxus commented 3 years ago

https://github.com/nrxus/faux/commit/c609864bded8b18809cf6c76d066a1db42b636c0 adds then_return for mocking without arguments. However there is not yet a way to pre-provide arguments.

nrxus commented 3 years ago

Closing in favor of #31