pgxmock v4 is out! Mocking batches for PostgreSQL in Go!
I am excited to announce the update of pgxmock v4! This update adds long awaited support for pgx.Batch
and completely rewrites the Prepare
and Deallocate
mocking implementation.
What are Batches?
Batch queries in pgx are a way of bundling multiple queries together to avoid unnecessary network round trips. A Batch
must only be sent once. One can define a function to deal with the results of every query, e.g.
batch := &pgx.Batch{}
batch.Queue("select some_func()").QueryRow(func(row pgx.Row) error {
var n int32
err := row.Scan(&n)
if err != nil {
return err
}
fmt.Println(n)
return err
})
batch.Queue("select * from foo*").Query(func(rows pgx.Rows) error {
// ...
})
batch.Queue("update foo set bar = 'zoo' where id = 1").Exec(func(ct pgconn.CommandTag) (err error) {
if ct.RowsAffected() != 1 {
err = errors.New("expected 1 row to be affected")
}
return
})
err = conn.SendBatch(ctx, batch).Close()
If a developer wants to have more control over result checking, they can use explicit way. This way the example above transforms to
batch := &pgx.Batch{}
batch.Queue("select some_func()")
batch.Queue("select * from foo*")
batch.Queue("update foo set bar = 'zoo' where id = 1")
br := mock.SendBatch(ctx, batch)
// process results
var n int32
err := br.QueryRow().Scan(&n)
if err != nil {
panic(err)
}
fmt.Println(n)
rows, err := br.Query()
if err != nil {
panic(err)
}
// ... process rows here
ct, err := br.Exec()
if err != nil {
panic(err)
}
if !ct.Update() || 1 == ct.RowsAffected() {
fmt.Println("something bad happened")
}
err := br.Close()
if err != nil {
panic(err)
}
And how am I supposed to test batches with pgxmock?
Really simple. Just as everything else. First, you define you expectations! Second, you call your function with a mock as an argument! And finally, you check if all expectations were met and if your code reacted as expected.
Let’s imagine we have a function to test
func processBatch(db pgx.Tx) err {
batch := &pgx.Batch{}
batch.Queue("select 1 + 1").QueryRow(func(row pgx.Row) error {
var n int32
return row.Scan(&n)
})
batch.Queue("update users set active = $1 where id = $2", true, 1).Exec(func(ct pgconn.CommandTag) (err error) {
if ct.RowsAffected() != 1 {
err = errors.New("expected 1 row to be affected")
}
return
})
return db.SendBatch(ctx, batch).Close()
}
func TestBatch(t *testing.T) {
t.Parallel()
mock, _ := NewConn()
a := assert.New(t)
// define our expectations
eb := mock.ExpectBatch()
eb.ExpectQuery("select").WillReturnRows(NewRows([]string{"sum"}).AddRow(2))
eb.ExpectExec("update").WithArgs(true, 1).WillReturnResult(NewResult("UPDATE", 1))
// run the test
err := processBatch(mock)
// check our expectations and code behaviour
a.NoError(err)
a.NoError(mock.ExpectationsWereMet())
}
Check pgxmock test cases to know more!
What about Prepare
and Deallocate
?
Since pgx doesn’t have a special struct to handle prepared statements, I simplified the ExpectPrepare
struct in pgxmock. Instead of this
mock.ExpectPrepare("articles_stmt", "SELECT (.+) FROM articles WHERE id = ?").
ExpectQuery().
WithArgs(1).
WillReturnRows(NewRows([]string{"id", "title"}).AddRow(1, "Betty B."))
one will just use this
mock.ExpectPrepare("authors_stmt", "SELECT (.+) FROM authors WHERE id = ?")
mock.ExpectQuery("authors_stmt").
WithArgs(1).
WillReturnRows(NewRows([]string{"id", "title"}).AddRow(1, "Betty B."))
Pretty simple, huh?
Ready to Upgrade?
I motivate all users to upgrade to pgxmock v4 to take advantage of these exciting enhancements and improvements. Whether you’re a long-time user or just starting with pgxmock, these changes will advance your PostgreSQL mocking experience.
To get started with pgxmock v4, check your import statement:
import "github.com/pashagolub/pgxmock/v4"
and/or run
go get -u github.com/pashagolub/pgxmock/v4
Thank you for your continued support and feedback. I look forward to seeing how pgxmock v4 empowers your PostgreSQL database testing. If you have any questions or need assistance with the upgrade, please contact me on GitHub.
Happy mocking!
Please, read and share! Glory to Ukraine! 💙💛