DATA-DOG / go-sqlmock

Sql mock driver for golang to test database interactions
Other
6.13k stars 407 forks source link

Testing Upsert... #218

Open rmawani opened 4 years ago

rmawani commented 4 years ago

Hi,

First off, I just wanted to thank you for creating such a wonderfully useful library! It has been a huge help to me.

Although I've managed to figure out most of the scenarios I've needed to test, the following one has been completely stumping me for the last week. Hopefully, somebody here will be able to help me out. Below is my code:

func UpsertRecords(records []Record) error {
    tx, err := DB.Begin()
    if err != nil {
        log.Printf("Begin Error")
    }

    txOK := false
    defer func() {
        if !txOK {
            tx.Rollback()
        }
    }()

    _, err = tx.Exec("CREATE TEMPORARY TABLE temp_records " +
                     "(serial VARCHAR, model VARCHAR) " +
                     "ON COMMIT DROP")
    if err != nil {
        log.Printf("TempTable Error")
    }

    sql, err := tx.Prepare(pq.CopyIn("temp_records", "serial", "model"))
    for _, val := range records {
        _, err = sql.Exec(val.Serial, val.Model, true)   // I get a Panic on this line
        if err != nil {
            log.Printf("Copy Error")
        }
    }

    _, err = sql.Exec()
    if err != nil {
        log.Printf("Flush Error")
    }
    err = sql.Close()
    if err != nil {
        log.Printf("Close Error")
    }

    _, err = tx.Exec("INSERT INTO records (serial, model) " +
                     "SELECT serial, model FROM temp_records " +
                     "ON CONFLICT (serial) DO UPDATE " +
                     "SET model = EXCLUDED.model")
    if err != nil {
        log.Printf("Move Error")
    }

    err = tx.Commit()
    if err != nil {
        log.Printf("Commit Error")
    }

    txOK = true
    return nil
}

And, here's my test below:

func TestShould_UpsertRecord (t *testing.T) {
    mockDB, mock, err := sqlmock.New()
    require.NoError(t, err, "Error - %v", err)
    defer mockDB.Close()

    DB = sqlx.NewDb(mockDB,"sqlmock")
    defer DB.Close()

    mock.ExpectBegin()
    mock.ExpectExec("CREATE TEMPORARY TABLE temp_records .*").
        WillReturnResult(sqlmock.NewResult(0,0))
    mock.ExpectPrepare("COPY temp_devices .*")
        ExpectExec().
        WillReturnResult(sqlmock.NewResult(0, 2))
        .
        .
        . /* This is where I get stuck and where I can't figure out how to handle the rest... */
        .
        .
    mock.ExpectCommit()
    mock.ExpectClose()

    assert.NoError(t, err)
}

I've tried so many things that I've now pretty much hit a brick wall and don't know where to go from here.

Anybody out there know how I can complete the above?

Thanks in advance!

R