go golang TDD Test-Driven Development Dependency Injection

看完前面的篇章

或許會覺得 測試就是這麼簡單啊

但是當你嘗試在專案裡面這樣使用的時候

會發現有許多問題要處理,好像沒有那麼簡單

以下面的 Code 為例, function 裡面用到了外部的 db

因為實際的 Database 的回應是不可控的

就無法保證每次的測試結果都會相同


  var db *gorm.DB

  func GetUserCount() (count int, err error) {
    err = db. // 這裡就用到了外部的 db, 測試時的不確定因數
        Table("customers").
        Count(&count).
        Error
    return
  }

解決這種不確定因數的方式,就是把 db 變成從外部傳入

這種手法就叫做 Dependency Injection(依賴性注入)

修改後的 Code


  func GetUserCount(db *gorm.DB) (count int, err error) {
    err = db. // 這時候 db 就是從外部傳進來,是可控的
        Table("customers").
        Count(&count).
        Error
    return
  }

另外一個問題是,就算是外部傳入,有時候也是很難控制

比如我們剛才在說的 Database,很難在測試的時候給出一個 Mock 的 Database

所以就要把 function 的輸入參數變成一個 Interface

就會更容易去 Mock


  // 現有程式碼
  type db struct {
    gorm.DB
  }

  func (d *db) Count() (count int, err error) {
    err = d.
      Table("customers").
      Count(&count).
      Error
    return
  }

  // 未使用 Mock 的 function
  func GetCount(d *db) (count int, err error) {
    return d.Count()
  }

  // Mock 的 interface
  type DataStore interface {
    Count() (count int, err error)
  }

  // 使用 Mock 的 function
  func GetCount(d DataStore) (count int, err error) {
    return d.Count()
  }

打完收工