Database interactions
Show the SQL queries a handler makes in its sequence diagram, with the x/db package.
The x/db package wraps any database/sql driver so that the queries made during a test are recorded and drawn in the sequence diagram.


Setup
import apitestdb "github.com/steinfletcher/apitest/x/db"Wrap and register the driver
Create a recorder, wrap the driver you already use, and register the wrapped driver under a new name. This example uses the pure Go modernc.org/sqlite driver, which registers itself as sqlite.
var recorder = apitest.NewTestRecorder()
func init() {
// wrap the driver, then register the wrapped version under a new name
sql.Register("sqlite-recorded", apitestdb.WrapWithRecorder("sqlite", recorder))
}
Open the database through the wrapped driver
Open the application's database with the new driver name, and pass the same recorder to the test with Recorder:
func TestGetTodo(t *testing.T) {
dsn := filepath.Join(t.TempDir(), "todos.db")
seedTodos(t, dsn)
// the app opens the database through the recording driver
db, err := sql.Open("sqlite-recorded", dsn)
if err != nil {
t.Fatal(err)
}
defer db.Close()
apitest.New("gets a todo").
Recorder(recorder).
Report(apitest.SequenceDiagram()).
Handler(newTodoAPI(db)).
Get("/todos/1").
Expect(t).
Status(http.StatusOK).
Body(`{"id": 1, "title": "write docs", "done": false}`).
End()
}
// seedTodos uses the plain driver so the setup queries stay out of the diagram.
func seedTodos(t *testing.T, dsn string) {
db, err := sql.Open("sqlite", dsn)
if err != nil {
t.Fatal(err)
}
defer db.Close()
_, err = db.Exec(`
CREATE TABLE todos (id INTEGER PRIMARY KEY, title TEXT, done BOOLEAN);
INSERT INTO todos (title, done) VALUES ('write docs', false);
`)
if err != nil {
t.Fatal(err)
}
}
Each query appears as a SQL Query message with its arguments, followed by a SQL Result message with the number of rows returned or affected. The participant is named after the wrapped driver.
Keep setup out of the diagram
Everything the wrapped driver does is recorded, including queries made before the test runs. The example seeds the database through the plain sqlite driver so that the inserts do not appear in the diagram. Alternatively, call recorder.Reset() after seeding. The recorder is reset after each report, so tests that share it start clean.
Connectors
Drivers that are opened with a driver.Connector, such as pgx through stdlib.GetConnector, can be wrapped with WrapConnectorWithRecorder. The second argument names the participant:
connector := apitestdb.WrapConnectorWithRecorder(pgxConnector, "postgres", recorder)
db := sql.OpenDB(connector)Examples
The apitest repository has complete examples for SQLite, MySQL and PostgreSQL.
For DynamoDB, see the apitest-dynamodb companion library.