pashagolub / pgxmock

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

pgxpool.Pool does not implement BeginTxFunc required by pgxmock.PgxPoolIface #111

Closed TheGrandmother closed 2 years ago

TheGrandmother commented 2 years ago

If I try to do something like this:

type Client struct {
    pool pgxmock.PgxPoolIface
}

func NewClient() *Client {
    pgUrl := "......"

    Pool, err := pgxpool.New(context.Background(), pgUrl)
    if err != nil {
        panic(err)
    }
    client := Client{pool}
    return &client
}

I get cannot use Pool (variable of type *pgxpool.Pool) as type pgxmock.PgxPoolIface in struct literal: *pgxpool.Pool does not implement pgxmock.PgxPoolIface (missing BeginTxFunc method)

The interface type provided by this package appears to be out of sync as https://github.com/jackc/pgx/blob/master/pgxpool/pool.go does not implement BeginTxFunc but pgxmock.PgxPoolIface inherits (or whatever it is called) it from pgxmock.pgxIface.

But I don't know, I am probably doing something wrong, I am a very inexperienced developer who is not mentally equipped to write go code.

pashagolub commented 2 years ago

Hello,

what versions of pgx and pgxmock are involved?

Thanks in advance!

bnelz commented 2 years ago

@pashagolub we are having the same issue on v5.1.0 of pgx and v2.3.0 of pgxmock.

pashagolub commented 2 years ago

Thanks. The quick workaround would be to create your own interface. And frankly speaking it's not worth to use pgxmock types and/or structs outside of tests

pashagolub commented 2 years ago

Here is the example of how this should be done in the real life. We define our own interface to use and pgxmock used only in tests.

package main

import (
    "context"

    pgx "github.com/jackc/pgx/v5"
    "github.com/jackc/pgx/v5/pgxpool"
)

type PgxIface interface {
    Begin(context.Context) (pgx.Tx, error)
    Close()
}

func recordStats(db PgxIface, userID, productID int) (err error) {
    tx, err := db.Begin(context.Background())
    if err != nil {
        return
    }

    defer func() {
        switch err {
        case nil:
            err = tx.Commit(context.Background())
        default:
            _ = tx.Rollback(context.Background())
        }
    }()

    if _, err = tx.Exec(context.Background(), "UPDATE products SET views = views + 1"); err != nil {
        return
    }
    if _, err = tx.Exec(context.Background(), "INSERT INTO product_viewers (user_id, product_id) VALUES (?, ?)", userID, productID); err != nil {
        return
    }
    return
}

func main() {
    // @NOTE: the real connection is not required for tests
    db, err := pgxpool.New(context.Background(), "postgres://rolname@hostname/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    if err = recordStats(db, 1 /*some user id*/, 5 /*some product id*/); err != nil {
        panic(err)
    }
}