簡體   English   中英

如何在Golang中模擬通過測試的方法

[英]How to mock method to pass test in golang

我正在為api(golang)設置單元測試。
似乎使用了嘲諷。 但是我不明白如何編碼才能成功。

article
  ├ client
  ├ api
  │  ├ main.go
  │  ├ contoroller
  │  │    ├ contoroller.go
  │  │    └ contoroller_test.go
  │  ├ service
  │  │    ├ service.go
  │  │    └ service_test.go
  │  ├ dao
  │  │    ├ dao.go
  │  │    └ dao_test.go
  │  ├ s3
  │  │    ├ s3.go
  │  │    └ s3_test.go
  │  ├ go.mod 
  │  ├ go.sum
  │  └ Dockerfile
  ├ nginx
  └ docker-compose.yml

現在,我嘗試設置dao_test.go但是它失敗了,因為dao.gos3.dao調用方法。

dao_test.go

package dao

// import

type DaoSuite struct {
    suite.Suite
    db   *sql.DB
    mock sqlmock.Sqlmock
    dao  *Dao
    s3   *s3.S3
}

func (s *DaoSuite) SetupTest() {

    var err error
    s.db, s.mock, err = sqlmock.New()
    s.Require().NoError(err)
    s.dao = NewDao(s.db, s.s3)
}

func (s *DaoSuite) TestDeleteArticleDao() {

    // some method

    // here test fails because DeleteArticleDao calls method from another package.
    s.dao.DeleteArticleDao("1")

}

func (s *DaoSuite) TearDownTest() {
    s.db.Close()
    s.Assert().NoError(s.mock.ExpectationsWereMet())
}

package dao

// import

type Dao struct {
    database *sql.DB
    s3       *s3.S3
}

func NewDao(database *sql.DB, s3 *s3.S3) *Dao {
    objs := &Dao{database: database, s3: s3}
    return objs
}

func (d *Dao) DeleteArticleDao(id string) {
    //generate imageName

    //here calls method in package s3
    //here test fails 
    d.s3.DeleteS3Image(imageName)

}

s3.go

package s3

//import

type S3 struct {
    APPID  string
    SECRET string
}

type DaoInterface interface {
    DeleteS3Image(imageName util.ImageName) error
}

func NewS3(appid, secret string) *S3 {
    objs := &S3{APPID: appid, SECRET: secret}
    return objs
}


func (objs *S3) DeleteS3Image(imageName util.ImageName) error {
    // method
}

完整的源代碼在這里(fix-test-dao):
https://github.com/jpskgc/article/tree/fix-test-dao

我希望dao_test.go的測試成功。
但是實際是失敗的,因為dao.gos3 package調用方法。
我想知道如何模擬s3包中的DeleteS3Image以避免錯誤和成功測試。

這是在dao_test.go運行go test -v時的dao_test.go

$ go test -v
--- FAIL: TestDaoSuite (0.00s)
    --- FAIL: TestDaoSuite/TestDeleteArticleDao (0.00s)
        dao_test.go:221: 
                Error Trace:    dao_test.go:221
                                                        suite.go:122
                                                        panic.go:522
                                                        panic.go:82
                                                        signal_unix.go:390
                                                        s3.go:66
                                                        dao.go:74
                                                        dao_test.go:156
                Error:          Received unexpected error:
                                there is a remaining expectation which was not matched: ExpectedBegin => expecting database transaction Begin
                Test:           TestDaoSuite/TestDeleteArticleDao
        suite.go:61: test panicked: runtime error: invalid memory address or nil pointer dereference

在您的設置中,您確實調用s.dao = NewDao(s.db, s.s3)但是您從未將s.s3初始化為任何東西,因此s.dao.s3仍然為nil ,這就是為什么d.s3.DeleteS3Image(imageName)恐慌。


為了能夠模擬方法,在Go中,調用該方法的值必須是接口,而不是具體類型。 換句話說,這是不可能的嘲笑中去的具體方法。

因此,使用這樣的類型:

type Dao struct {
    database *sql.DB
    s3       *s3.S3
}

您根本無法嘲笑s3

您可以做的是將s3字段的類型更改為一種接口類型,您已經准備好了( s3.DaoInterface )。

type Dao struct {
    database *sql.DB
    s3       s3.DaoInterface
}

現在您可以模擬s3字段。

剩下的就是您要實現模擬並確保在測試設置過程中將s3字段設置為模擬實現的實例。

type MockS3 struct{}

func (MockS3) DeleteS3Image(imageName util.ImageName) error {
    // do whatever
    return nil
}

func (s *DaoSuite) SetupTest() {

    var err error
    s.db, s.mock, err = sqlmock.New()
    s.Require().NoError(err)
    s.dao = NewDao(s.db, s.s3)
    s.dao.s3 = MockS3{} // <- don't forget about me
}

這取決於您如何實現模擬,但是如果您是模擬的新手,我建議您看一下https://github.com/golang/mock來幫助您生成模擬。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM