[英]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.go
從s3.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.go
從s3 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.