gpt4 book ai didi

unit-testing - 如何在golang中模拟方法以通过测试

转载 作者:行者123 更新时间:2023-12-03 03:15:43 24 4
gpt4 key购买 nike

我正在为 api(golang) 设置单元测试。
看来是用了mocking。但我不明白如何编码才能成功。

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())
}

dao.go

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 包 中的方法。
我想知道如何在包 s3 中模拟 DeleteS3Image 以避免错误和成功测试。

这是在 dao_test.go 运行 go test -v 时出现的错误。

$ 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) 出现 panic 的原因。

<小时/>

在 Go 中,为了能够模拟方法,调用该方法的值必须是接口(interface),而不是具体类型。换句话说,在 Go 中模拟具体方法是不可能的。

因此,使用这样的类型:

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

你根本无法模拟s3

您可以做的是将 s3 字段的类型更改为接口(interface)类型,您已经准备好了一个 (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帮助您生成模拟。

关于unit-testing - 如何在golang中模拟方法以通过测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57829913/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com