I am using Testify to mock a Postgres database for testing.
I cannot create a unit test in Testify if the GORM operation is chained. In this example, I am using “Where” and “Delete” operation.
This is the function I am testing:
func (r *Repository) DeleteUser(id uint) error {
result := r.db.DB.Where(&model.User{ID: id}).Delete(&model.User{})
if result.Error != nil || result.RowsAffected != 1 {
return result.Error
}
return nil
}
The Interface definition I have for the gormDB Mock Where and Delete is as follows:
func (m *GormDBMock) Delete(value interface{}, where ...interface{}) *gorm.DB {
args := m.Called(append([]interface{}{value}, where...)...)
return args.Get(0).(*gorm.DB)
}
func (m *GormDBMock) Where(query interface{}, args ...interface{}) *gorm.DB {
callArgs := m.Called(append([]interface{}{query}, args...)...)
return callArgs.Get(0).(*gorm.DB)
}
[...]
// Ensure GormDBMock implements the DBInterface
var _ database.DBInterface = &GormDBMock{}
And the database mock I use is as follows:
type DatabaseMock struct {
mock.Mock
DB *GormDBMock
}
func (m *DatabaseMock) New(credential config.Credential) *database.Database {
args := m.Called(credential)
return args.Get(0).(*database.Database)
}
func (m *DatabaseMock) Close() {
m.Called()
}
And this is the database interface:
type DBInterface interface {
Delete(value interface{}, where ...interface{}) *gorm.DB
Where(query interface{}, args ...interface{}) *gorm.DB
Transaction(fc func(tx *gorm.DB) error, opts ...*sql.TxOptions) error
Model(value interface{}) *gorm.DB
}
// Ensure *gorm.DB implements the interface
var _ DBInterface = &gorm.DB{}
This is the unit test I have written:
func TestDeleteUser(t *testing.T) {
// Create instance of gorm DB mock
gormDBMock := new(mocks.GormDBMock)
// Sample data
georgeWashington := model.User{
ID: 1,
Name: "George Washington",
Email: "[email protected]",
PhoneNumber: "+1234567890",
Password: "password",
Role: "Admin",
}
// Test data
userID := georgeWashington.ID
// Set up the chained call: Where -> Delete
gormDBMock.On("Where", mock.MatchedBy(func(user *model.User) bool {
return user.ID == userID
})).Return(gormDBMock)
gormDBMock.On("Delete", &model.User{}).Return(&gorm.DB{RowsAffected: 1, Error: nil})
// Create instance of database mock (which contains the gorm DB mock)
dbMock := &database.Database{DB: gormDBMock}
// Create repository instance
repo := repository.New(dbMock)
// Call the method being tested
err := repo.DeleteUser(userID)
// Check results
assert.NoError(t, err)
gormDBMock.AssertExpectations(t)
}
Whenever I run the code, the following error always show up:
--- FAIL: TestDeleteUser (0.00s)
panic: interface conversion: interface {} is *mocks.GormDBMock, not *gorm.DB [recovered]
panic: interface conversion: interface {} is *mocks.GormDBMock, not *gorm.DB
Would someone please help me to show the correct way to do the chained call? i.e. how to do the gormDBMock.On(“Where”)… and gormDBMock.On(“Delete”)… correctly?
Thank you!
Stephen is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.