DB Mocking in one Go test case is interfering with other test case

771 Views Asked by At

I have two Go test cases as shown below that test a gRPC function called MyEndpoint.

MyEndpoint is supposed to succeed when the database row it selects has Field1 == "A" and return an error otherwise.

I'm mocking out the database with the go-sqlmock package from Data-dog.

package mypackage_test

import (
    "github.com/DATA-DOG/go-sqlmock"
    "github.com/stretchr/testify/require"
)


type MyEntity struct {
    Id                     sql.NullInt32 `db:"id"`  
    Field1                 sql.NullString `db:"field1"`
    Field2                 sql.NullString `db:"field2"`
    Field3                 sql.NullString `db:"field3"`
}

var Columns = []string{
    "id",
    "field_1",
    "field_2",
    "field_3"
}



var dbRow = []driver.Value{int32(999), "A", "B", "C"]


func TestMyTestA(t *testing.T) {
    t.Run("Verify MyEndpoint Fails when mocked Database row has Field1 != A", func(t *testing.T) {
        api, err := getMyAPI()
        require.Nil(t, err)
        defer api.Close()

        api.DBMock.ExpectBegin()
        api.DBMock.MatchExpectationsInOrder(false)

        modifiedDBRow := dbRow
        modifiedDBRow[0] = "Z"
        api.DBMock.ExpectQuery("SELECT").
            WithArgs(int32(999)).WillReturnRows(sqlmock.NewRows(Columns).AddRow(modifiedDBRow...))
        api.DBMock.ExpectCommit()
        
        _, err = ... // Call MyEndpoint with parameter Id: int32(999)
        api.DBMock.ExpectClose()
        require.NotNil(t, err)
    })
}

func TestMyTestB(t *testing.T) {
    t.Run("Verify MyEndpoint succeeds when mocked Database row has Field1 == A", func(t *testing.T) {
        api, err := getMyAPI()
        require.Nil(t, err)
        defer api.Close()

        api.DBMock.ExpectBegin()
        api.DBMock.MatchExpectationsInOrder(false)

        api.DBMock.ExpectQuery("SELECT").
            WithArgs(int32(999)).WillReturnRows(sqlmock.NewRows(Columns).AddRow(dbRow...))
        api.DBMock.ExpectCommit()
        
        _, err = ... // Call MyEndpoint with parameter Id: int32(999)
        api.DBMock.ExpectClose()
        require.Nil(t, err)
    })
}

When I run these two test cases individually, they both pass.

But when I run them together, TestMyTestB fails because it thinks Field1 == "Z". So clearly TestMyTestA is interfering with TestMyTestB. Why?

It seems that the mocking done in TestMyTestA case is still in effect when it gets to TestMyTestB and the mocking I'm doing in TestMyTestB case is completely ignored.

How can I mock these two test cases out independently of one another?

1

There are 1 best solutions below

2
On BEST ANSWER

It's because of an incorrect assignment to modifiedDBRow slice in your first test. Remember that a slice does not store any data, it just describes a section of an underlying array.

So when you modified modifiedDBRow in the first test, you've inherently modified the underlying array containing value at [0], from A to Z, which persists when you read the dbRow in your next test. Either reset the value at the end of the first test or have a different set of variables to use across tests.