mockall icon indicating copy to clipboard operation
mockall copied to clipboard

How would one mock the following trait using automock/mock!??

Open ealders opened this issue 10 months ago • 4 comments

pub trait DbSessionTrait {
      async fn query_as<T>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
      async fn query(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
      async fn validate_schema_exists(&self, schema: &str) -> Result<bool, Error>;
    }

Looking for the best way to mock out this trait for unit testing... it does not seem to work with the automock or mock!. Wanted to get some advice on a way to mock this out even if I needed to build it out manually.

ealders avatar Feb 07 '25 23:02 ealders

What error do you get when using #[automock]? I suspect that you'll have to add a : 'static bound to T.

asomers avatar Feb 07 '25 23:02 asomers

Here's a dump from the compiler with 'static in there

error[E0106]: missing lifetime specifier
   --> src/modules/db.rs:207:64
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                                                                ^ expected named lifetime parameter
    |
help: consider using the `'__mockall_params` lifetime
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[&'__mockall_params  (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                                                                 +++++++++++++++++

error[E0637]: `&` without an explicit lifetime name cannot be used here
   --> src/modules/db.rs:207:64
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                                                                ^ explicit lifetime name needed here
    |
help: consider introducing a higher-ranked lifetime here
    |
205 ~   for<'a> #[automock]
206 |   pub trait DbSessionTrait {
207 ~     async fn query_as<T:'static>(&self, query: &str, params: &[&'a  (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |

error[E0261]: use of undeclared lifetime name `'__mockall_params`
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^- lifetime `'__mockall_params` is missing in item created through this procedural macro
    |   |
    |   undeclared lifetime
206 |   pub trait DbSessionTrait {
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                       - help: consider introducing lifetime `'__mockall_params` here: `'__mockall_params,`
    |
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0106]: missing lifetime specifier
   --> src/modules/db.rs:208:50
    |
208 |     async fn query(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |                                                  ^ expected named lifetime parameter
    |
help: consider using the `'__mockall_params` lifetime
    |
208 |     async fn query(&self, query: &str, params: &[&'__mockall_params  (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |                                                   +++++++++++++++++

error[E0637]: `&` without an explicit lifetime name cannot be used here
   --> src/modules/db.rs:208:50
    |
208 |     async fn query(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |                                                  ^ explicit lifetime name needed here
    |
help: consider introducing a higher-ranked lifetime here
    |
205 ~   for<'a> #[automock]
206 |   pub trait DbSessionTrait {
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
208 ~     async fn query(&self, query: &str, params: &[&'a  (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |

error: `impl` item signature doesn't match `trait` item signature
   --> src/modules/db.rs:207:5
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     found `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&(dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> impl futures_core::Future<Output = Result<Vec<T>, tokio_postgres::Error>>`
    |     expected `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&dyn tokio_postgres::types::ToSql + Sync]) -> _`
    |
    = note: expected signature `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&dyn tokio_postgres::types::ToSql + Sync]) -> _`
               found signature `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&(dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> impl futures_core::Future<Output = Result<Vec<T>, tokio_postgres::Error>>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
   --> src/modules/db.rs:207:101
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                                                                                                     ^ consider borrowing this type parameter in the trait

error: `impl` item signature doesn't match `trait` item signature
   --> src/modules/db.rs:208:5
    |
208 |     async fn query(&self, query: &str, params: &[& (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
    |     |
    |     found `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&(dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> impl futures_core::Future<Output = Result<Vec<tokio_postgres::Row>, tokio_postgres::Error>>`
    |     expected `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&dyn tokio_postgres::types::ToSql + Sync]) -> _`
    |
    = note: expected signature `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&dyn tokio_postgres::types::ToSql + Sync]) -> _`
               found signature `fn(&'1 MockDbSessionTrait, &'2 str, &'3 [&(dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> impl futures_core::Future<Output = Result<Vec<tokio_postgres::Row>, tokio_postgres::Error>>`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output

error[E0277]: the trait bound `for<'__mockall_params> MockallMatcher1: Predicate<[&'__mockall_params (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]>` is not satisfied
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^ the trait `for<'__mockall_params> Predicate<[&'__mockall_params (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]>` is not implemented for `MockallMatcher1`
    |
    = note: required for the cast from `Box<MockallMatcher1>` to `Box<dyn Predicate<[&dyn ToSql + Sync]> + Send>`
    = note: the full name for the type has been written to '/Users/ealders/code/strenuus/provider-nexus-api/target/debug/deps/provider_nexus-e0e2438c84565d24.long-type-6529247397761219127.txt'
    = note: consider using `--verbose` to print the full type name to the console
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `for<'__mockall_params> MockallMatcher1: Predicate<[&'__mockall_params (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]>` is not satisfied
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^ the trait `for<'__mockall_params> Predicate<[&'__mockall_params (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]>` is not implemented for `MockallMatcher1`
    |
    = note: required for the cast from `Box<MockallMatcher1>` to `Box<dyn Predicate<[&dyn ToSql + Sync]> + Send>`
    = note: the full name for the type has been written to '/Users/ealders/code/strenuus/provider-nexus-api/target/debug/deps/provider_nexus-e0e2438c84565d24.long-type-192473539372891870.txt'
    = note: consider using `--verbose` to print the full type name to the console
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

ealders avatar Feb 07 '25 23:02 ealders

Those errors are saying that you need to add a lifetime parameter to the references in your function arguments. The easiest one to add is 'static. Can you do that?

asomers avatar Feb 07 '25 23:02 asomers

Yeah... it looks like it is conflicting with the lifetime added by automock.

error[E0261]: use of undeclared lifetime name `'__mockall_params`
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^- lifetime `'__mockall_params` is missing in item created through this procedural macro
    |   |
    |   undeclared lifetime
206 |   pub trait DbSessionTrait {
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[&'static (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |                       - help: consider introducing lifetime `'__mockall_params` here: `'__mockall_params,`
    |
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: method not compatible with trait
   --> src/modules/db.rs:207:5
    |
207 |     async fn query_as<T:'static>(&self, query: &str, params: &[&'static (dyn ToSql + Sync)]) -> Result<Vec<T>, Error>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected signature `fn(&MockDbSessionTrait, &_, &[&'static (dyn tokio_postgres::types::ToSql + Sync + 'static)]) -> _`
               found signature `fn(&MockDbSessionTrait, &_, &[&'static (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> _`
note: the lifetime `'__mockall_params` as defined here...
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^
    = note: ...does not necessarily outlive the static lifetime
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: method not compatible with trait
   --> src/modules/db.rs:208:5
    |
208 |     async fn query(&self, query: &str, params: &[&'static (dyn ToSql + Sync)]) -> Result<Vec<Row>, Error>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
    |
    = note: expected signature `fn(&MockDbSessionTrait, &_, &[&'static (dyn tokio_postgres::types::ToSql + Sync + 'static)]) -> _`
               found signature `fn(&MockDbSessionTrait, &_, &[&'static (dyn tokio_postgres::types::ToSql + Sync + '__mockall_params)]) -> _`
note: the lifetime `'__mockall_params` as defined here...
   --> src/modules/db.rs:205:3
    |
205 |   #[automock]
    |   ^^^^^^^^^^^
    = note: ...does not necessarily outlive the static lifetime
    = note: this error originates in the attribute macro `automock` (in Nightly builds, run with -Z macro-backtrace for more info)

ealders avatar Feb 07 '25 23:02 ealders