I'm writing unit tests with database in Go.
My models have several layers and it's like Tour has a many-to-many relationship with Collect and Collect has a many-to-many relationship with Song too.
How do I write such tests and generate test cases efficiently? I'm using go-sqlmock to mock queries, however, since that models have foreign keys so that I need to generate at least 3 mock queries for a single test case.
I've studied table-driven tests that official recommends, however, I think it's much harder for my cases.
Below are some code for your information.
type Tour struct {
gorm.Model `json:"-"`
Collects []*Collect `gorm:"many2many:tour_collects;" json:"collects"`
}
type Collect struct {
gorm.Model `json:"-"`
Title string `json:"title"`
Songs []*Song `gorm:"many2many:collect_songs;" json:"songs"`
FrontendID uint `json:"id"`
}
func GetTour(id int) (*Tour, error) {
var tour Tour
err := db.Preload("Collects").Where("id = ?", id).First(&tour).Error
if err != nil {
return nil, err
}
return &tour, nil
}
func TestGetTourSuccess(t *testing.T) {
mock := setupTestDatabase(t)
if mock == nil {
return
}
mock.ExpectQuery("SELECT (.+) FROM `tours` WHERE (.+) AND `tours`.`deleted_at` IS NULL ORDER BY `tours`.`id` LIMIT 1").
WithArgs(1).
WillReturnRows(
sqlmock.NewRows(tourColumns).AddRow(1, time.Now(), time.Now(), nil),
)
mock.ExpectQuery("SELECT (.+) FROM `tour_collects` WHERE `tour_collects`.`tour_id` = \\?").
WithArgs(1).WillReturnRows(
sqlmock.NewRows([]string{"tour_id", "collect_id"}).AddRow(1, 1).AddRow(1, 2).AddRow(1, 3),
)
mock.ExpectQuery("SELECT (.+) FROM `collects`").WithArgs(testCollectID...).WillReturnRows(sqlmock.NewRows(collectColumns).
AddRow(1, time.Now(), time.Now(), nil, "hello").
AddRow(2, time.Now(), time.Now(), nil, "world").
AddRow(3, time.Now(), time.Now(), nil, "hi"))
tour, err := GetTour(1)
if err != nil {
t.Error("errors happened when get tour: ", err.Error())
}
if tour.ID != 1 {
t.Error("error that tour id is not matched")
}
for i := range tour.Collects {
if v := testCollectID[i].(int); v != int(tour.Collects[i].ID) {
t.Error("collect id is not matched", v, int(tour.Collects[i].ID))
}
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Error("errors that expectations were not met: ", err.Error())
}
}