Using Diesel with Rocket usually require the use of rocket_sync_db_pools crate which hides the complicated setup of initializing a DB connection pool and expose it to handlers via a opaque type that you can call run on to get a Future back and only in that Future you will get a connection.

This makes writing a integration test with a Rocket handler a bit more complicated because the impl of the DB Pool guard type is generated on-the-fly and not bind to a trait, so we can’t just write a mock implementation of it.

After some trial and error, I realized that you can initialize Rocket to the Ignite state (initialized but not launched/listening yet). We generate a new test DB on-the-fly for every test so we also need to config the Rocket instance to use the right test-specific DB url. Here’s the code doing so:

pub async fn rocket_test<F, Fut, R>(&self, f: F) -> anyhow::Result<R>
  F: FnOnce(DbConnection) -> Fut,
  Fut: Future<Output = R> + Send + 'static,
  R: Send + 'static,
  let figment = rocket::Config::figment()
    .merge(("databases.db.url", self.db_url.clone()));
  let rocket = rocket::custom(figment)
  let conn = DbConnection::get_one(&rocket)
      "unable to get db connection".to_string(),
  let result = f(conn).await;

and therefore, you can write tests as such:

rocket_test(async move |conn| {
  let ret = a_rocket_handler(
  .expect_err("handler should fail");