Sqlx: #[sqlx::test]

Created on 21 May 2020  路  3Comments  路  Source: launchbadge/sqlx

Thought of this one a while ago before public release but it didn't make it to this issue tracker.

Basically enables this pattern:

#[sqlx::test]
async fn test_use_database(conn: PgConnection) -> anyhow::Result<()> {
    // ... test code here
}

Where the emitted code is equivalent to something like this:

#[tokio::test] // or `#[async_std::test]` depending on which runtime feature is activated
async fn test_use_database() -> anyhow::Result<()> {
    use sqlx::Connect;

    // ideally this should be a more useful error as `VarError` does not report the variable in question, making the message useless
    let database_url = dotenv::var("DATABASE_URL")?;

    // implementation note: for the identifier make sure to reuse the exact token that was given for the arg name in the input so this obeys hygiene and can be referenced by the test code
    let conn: PgConnection = sqlx::Connect::connect(database_url).await?;

    // ... test code here
}

@mehcode has a version of this on develop already, although it only covers the #[tokio::test]/#[async_std::test] part (which effectively just inlines what those attributes do): https://github.com/launchbadge/sqlx/blob/develop/sqlx-rt-macros/src/lib.rs

The only real question I think is what to do as far as the error from dotenv::var() because the error that's emitted is not helpful at all in the case of DATABASE_URL not being defined, and would be compounded by the fact that the user wouldn't be able to immediately see the code where it came from.

My current best idea is to add a (hidden?) variant to sqlx::Error, since the function result's error type would need to be convertible from sqlx::Error _anyway_ for the connect() call and any calls that actually use the connection. Some users will probably elect to just use sqlx::Result anyway.

E-medium enhancement proposal

Most helpful comment

I agree with the transaction but the attribute should accept an argument to disable this for stuff that doesn't work in a transaction (I'm not sure what).

#[sqlx::test(in_tx = false)] (Bikeshedding?)

All 3 comments

We should put the connection into a never-committed transaction. The general idea is anything done to the test transaction is not visible outside that test.

See http://docs.diesel.rs/diesel/connection/trait.Connection.html#method.begin_test_transaction for a similar concept in Diesel.


Additionally, we should probably add a way to create a singleton Pool ( singleton meaning the pool has a single connection it manages and doesn't ever add any more ) from a connection like PgPool::singleton(conn) ( bikeshedding on the name there welcome ) so someone can utilize sqlx::test with a test structure that wants a pool.

I agree with the transaction but the attribute should accept an argument to disable this for stuff that doesn't work in a transaction (I'm not sure what).

#[sqlx::test(in_tx = false)] (Bikeshedding?)

We should put the connection into a never-committed transaction. The general idea is anything done to the test transaction is not visible outside that test.

See http://docs.diesel.rs/diesel/connection/trait.Connection.html#method.begin_test_transaction for a similar concept in Diesel.

Was this ever implemented? I'm looking for a way to do this with sqlx (I used to do it in Diesel with the linked method) but I don't see anything in sqlx-test's source code that would do this.

Edit: BTW, it would be helpful to have documentation for sqlx::pool::PoolOptions::{after_connect, before_acquire, after_release} and examples of usage. In Diesel I used a similar "on acquire" hook to achieve test transactions, so I thought this might be the way to do it in sqlx, but wasn't able to figure it out. I was also puzzled by the Fut generic parameter to before_acquire, which doesn't seem to be used anywhere in the signature. My attempts to use the function kept failing with type inference errors because the type of Fut couldn't be determined.

Was this page helpful?
0 / 5 - 0 ratings