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! 💙💛