pashagolub / pgxmock

pgx mock driver for golang to test database interactions
Other
393 stars 49 forks source link

need help #31

Closed jadahbakar closed 3 years ago

jadahbakar commented 3 years ago

Hello, pashagolub If may i ask about pgxmock, i've using it in journey of learning golang

This is my repository.go

type propinsiRepository struct {
    DB *pgx.Conn
}

func NewPropinsiRepository(db *pgx.Conn) PropinsiRepository {
    return &propinsiRepository{DB: db}
}

func (pr *propinsiRepository) FindById(Id int) (*Propinsi, error) {
    var p *Propinsi
    query := pr.DB.QueryRow(context.Background(), "SELECT propinsi_id, propinsi_nama FROM mst.propinsi WHERE propinsi_id=$1", Id)
    if err := query.Scan(&p.PropinsiId, &p.PropinsiNama); err != nil {
        return nil, err
    }
    return p, nil
}

and this is repository_test.go


func TestFindById(t *testing.T) {
    mock, err := pgxmock.NewConn()
    if err != nil {
        t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
    }
    defer mock.Close(context.Background())
    rows := mock.NewRows([]string{"propinsi_id", "propinsi_nama"}).AddRow(1, "test_propinsi_nama")
    query := "SELECT propinsi_id, propinsi_nama FROM mst.propinsi WHERE propinsi_id=\\?"
    propinsiID := int(1)
    mock.ExpectQuery(query).WithArgs(propinsiID).WillReturnRows(rows)
    repo := repository.NewPropinsiRepository(mock.Conn())
    anPropinsi, err := repo.FindById(propinsiID)
    assert.NoError(t, err)
    assert.NotNil(t, anPropinsi)
}

There is no error warning, when i inject mock.Conn() on NewPropinsiRepository, but when i try to test, there is an error occured

panic: Conn() is not available in pgxmock [recovered]
    panic: Conn() is not available in pgxmock

i'm still new in golang, and i'm so thankful for your support.

fabiothiroki commented 3 years ago

@jadahbakar from what I've understood of pgxmock, you shouldn't rely directly on pgx.Conn on your repository, but use an interface. In this case, you can use the pgxmock.PgxConnIface from pgxmock itself. So on tests you shouldn't need to call mock.Conn(), but use pgxmock.NewConn() instead

I think your code has some issues when scanning the row to the Propinsi struct that was leading to a segmentation fault. I also changed the query matcher to use a regexp.

In my working code, I changed everything to be contained in the same package just to facilitate my environment setup:

// repository.go
package database

import (
    "context"

    "github.com/pashagolub/pgxmock"
)

type Propinsi struct {
    PropinsiId   int
    PropinsiNama string
}

type PropinsiRepository struct {
    DB pgxmock.PgxConnIface
}

func NewPropinsiRepository(db pgxmock.PgxConnIface) *PropinsiRepository {
    return &PropinsiRepository{DB: db}
}

func (pr *PropinsiRepository) FindById(Id int) (*Propinsi, error) {
    p := &Propinsi{}
    query := pr.DB.QueryRow(context.Background(), "SELECT propinsi_id, propinsi_nama FROM mst.propinsi WHERE propinsi_id=$1", Id)
    if err := query.Scan(&p.PropinsiId, &p.PropinsiNama); err != nil {
        return nil, err
    }
    return p, nil
}
// repository_test.go
package database

import (
    "context"
    "testing"

    "github.com/pashagolub/pgxmock"
    "github.com/stretchr/testify/assert"
)

func TestFindById(t *testing.T) {
    mock, err := pgxmock.NewConn()
    if err != nil {
        t.Fatalf("an error '%s' was not expected when opening a stub database connection", err)
    }
    defer mock.Close(context.Background())
    rows := mock.NewRows([]string{"propinsi_id", "propinsi_nama"}).AddRow(1, "test_propinsi_nama")
    query := "^SELECT propinsi_id, propinsi_nama FROM mst.propinsi WHERE propinsi_id="
    propinsiID := int(1)
    mock.ExpectQuery(query).WithArgs(propinsiID).WillReturnRows(rows)
    repo := NewPropinsiRepository(mock)
    anPropinsi, err := repo.FindById(propinsiID)
    assert.NoError(t, err)
    assert.NotNil(t, anPropinsi)
}
jadahbakar commented 3 years ago

Hello @fabiothiroki Thank you for your response and answering it,

func NewPropinsiRepository(db pgxmock.PgxConnIface) *PropinsiRepository {
    return &PropinsiRepository{DB: db}
}

did you mean

func NewPropinsiRepository(db pgxmock.PgxConnIface) PropinsiRepository {
    return &propinsiRepository{DB: db}
}

because

type PropinsiRepository interface {
    FindAll() ([]*Propinsi, error)
    FindById(Id int) (*Propinsi, error)
}