pgsnap

package module
v0.0.0-...-9adfbcf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2023 License: MIT Imports: 20 Imported by: 1

README

pgsnap

Fake PostgreSQL proxy for unit testing

Getting Started

You can download the library in by typing this command

go get github.com/egon12/pgsnap

and then use it in test

package db

import (
  "database/sql"
  "testing"
  
  "github.com/egon12/pgsnap"
  "github.com/lib/pq"
)

func TestDB_GetProduct(t *testing.T) {
  snap := pgsnap.NewSnap(t, "postgresql://user:password@localhost:5432/dbname")
  defer snap.Finish()
  
  db, _ := sql.Open(snap.Addr())

  p := ProductRepo{DB: db}
  p, err := p.Get(1)

  if err != nil {
    t.Errorf("got error: %v", err)
  }

  if p.ID != 1 {
    t.Error("got wrong product")
  }
}

How does it work?

When we create pgsnap, we will create a postgresql proxy, that will be used to get message that send/receive between app and postgres. At first run, or when we don't have the snapshot file, it will create the snapshot file and save it.

At the second run the proxy would not connect to the real postgres server, and instead read the snapshot file and response accordingly to the app.

First run
graph LR

    TestApp --> pgsnap.Proxy --> postgreSQL_Server
    postgreSQL_Server --> pgsnap.Proxy --> TestApp
    pgsnap.Proxy --> snapshot_file
    
Second run (and run in CI/CD environment)
graph LR

    TestApp --> pgsnap.Proxy --> snapshot_file
    snapshot_file --> pgsnap.Proxy --> TestApp
    
Refresh snapshot file

To recreate the snapshot_file you can delete the snapshot file run the test with environment variable PGSNAP_FORCE_WRITE=true like below

PGSNAP_FORCE_WRITE=true go test

Why we need this?

The best way to test PostgreSQL is by using real DB. Why? because the one that can predict correctness in queries are the DB itself. But it comes with a large baggage. Using DB as testing is quite hard, because we need to maintain the DB content while we do the testing.

The snapshot testing is inspired by snapshot testing UI using jest. In jest, to create the code at first we will use real UI (browser). And then when we do test, we will create some snapshot (tree structure of the UI). And every time we do some test, it will try to matched with snapshot that we have.

Known Bugs
  • For now, we only support github.com/lib/pq. This caused by different implementation in creating transaction statement. In lib/pq transaction is not named. But in jackc/pgx, the transaction is named by incremental singleton value. So there are possibility first run and second run have different value. Depends on how many query already run he test process.
  • When we don't interact with database in test it will have empty script.
  • Empty script not working well
  • When expectation is not match, sometimes it can get into waiting forever

Documentation

Index

Constants

This section is empty.

Variables

View Source
var EmptyScript = errors.New("script is empty")

Functions

func IsSnapshotExists

func IsSnapshotExists(t testing.TB) bool

Types

type Config

type Config struct {
	// TestTimeout Default 5s
	TestTimeout time.Duration

	// Force to create proxy and connect to real postgres server
	ForceWrite bool

	// Debug if true it will print more verbose
	Debug bool
}

type Snap

type Snap struct {
	// contains filtered or unexported fields
}

func NewDB

func NewDB(t testing.TB, url string) (*sql.DB, *Snap)

NewDB will create *sql.DB to be used in the test

func NewDBWithConfig

func NewDBWithConfig(t testing.TB, url string, cfg Config) (*sql.DB, *Snap)

NewDBWithConfig will create *sql.DB to be used in the test but it will ignore the snapshot file

func NewSnap

func NewSnap(t testing.TB, postgreURL string) *Snap

NewSnap will create snap

func NewSnapWithConfig

func NewSnapWithConfig(t testing.TB, url string, cfg Config) *Snap

Make it private first, because we still design the api first

func NewSnapWithForceWrite

func NewSnapWithForceWrite(t testing.TB, url string, forceWrite bool) *Snap

Deprecated NewSnapWithForceWrite function

func (*Snap) AddFinishFunc

func (s *Snap) AddFinishFunc(f func() error)

AddFinishFunc will add function that will be called when Finish() is called. It used by docker to remove container

func (*Snap) Addr

func (s *Snap) Addr() string

Addr will return proxy / fake postgres address in form of postgres://user:password@127.0.0.1:15432/postgres

func (*Snap) Finish

func (s *Snap) Finish()

Directories

Path Synopsis
docker module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL