3

I am trying to work on a web app with Diesel and Rocket, by following the rocket guide. I have not able to understand how to do testing of this app.

//in main.rs

#[database("my_db")]
struct PgDbConn(diesel::PgConnection);

#[post("/users", format="application/json", data="<user_info>")]
fn create_new_user(conn: PgDbConn, user_info: Json<NewUser>) {
    use schema::users;
    diesel::insert_into(users::table).values(&*user_info).execute(&*conn).unwrap();
}

fn main() {
    rocket::ignite()
        .attach(PgDbConn::fairing())
        .mount("/", routes![create_new_user])
        .launch();
}

// in test.rs

use crate::PgDbConn;

#[test]
fn test_user_creation() {
    let rocket = rocket::ignite().attach(PgDbConn::fairing());
    let client = Client::new(rocket).unwrap();
    let response = client
        .post("/users")
        .header(ContentType::JSON)
        .body(r#"{"username": "xyz", "email": "temp@abc.com"}"#)
        .dispatch();
    assert_eq!(response.status(), Status::Ok);
}

But this modifies the database. How can I make sure that the test does not alter the database.

I tried to create two database and use them in the following way(I am not sure if this is recommended)

#[cfg(test)]
#[database("test_db")]
struct PgDbConn(diesel::PgConnection);

#[cfg(not(test))]
#[database("live_db")]
struct PgDbConn(diesel::PgConnection);

Now I thought I can use the test_transaction method of the diesel::connection::Connection trait in the following way:-

use crate::PgDbConn;

#[test]
fn test_user_creation() {
    // !!This statment is wrong as PgDbConn is an Fn object instead of a struct
    // !!I am not sure how it works but it seems that this Fn object is resolved 
    // !!into struct only when used as a Request Guard
    let conn = PgDbConn;
    
    // Deref trait for PgDbConn is implemented, So I thought that dereferencing 
    // it will return a diesel::PgConnection
    (*conn).test_transaction::<_, (), _>(|| {
        let rocket = rocket::ignite().attach(PgDbConn::fairing());
        let client = Client::new(rocket).unwrap();
        let response = client
            .post("/users")
            .header(ContentType::JSON)
            .body(r#"{"username": "Tushar", "email": "temp@abc.com"}"#)
            .dispatch();
        assert_eq!(response.status(), Status::Ok);
        Ok(())
    });
}

The above code obviously fails to compile. Is there a way to resolve this Fn object into the struct and obtain the PgConnection in it. And I am not even sure if this is the right to way to do things.

Is there a recommended way to do testing while using both Rocket and Diesel?

CeNiEi
  • 97
  • 1
  • 5

1 Answers1

1

This will fundamentally not work as you imagined there, as conn will be a different connection than whatever rocket generates for you. The test_transaction pattern assumes that you use the same connection for everything.

weiznich
  • 2,910
  • 9
  • 16
  • Yes, after a bit more asking, I came to know that the route handler will open a separate connection and will commit the test data into the database; and hence it does not make sense to use `test_transaction`. So Is there no way by which we can test if the data is being correctly entered into the database AND restore the database to the previous state at the same time? – CeNiEi Feb 08 '22 at 15:08