How to unit test a model with foreign keys?

Viewed 935

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())
    }
}
0 Answers
Related