英文:
Golang dependency injection for mock database in unit testing
问题
我正在创建一个使用Golang接口的模拟数据库,以测试我的处理程序函数。然而,在我的单元测试环境中,我似乎没有正确执行依赖注入。我创建了一个setup_test.go
文件来设置我的模拟数据库环境。在下面的代码片段中,我将介绍我的依赖注入的流程。
main.go
package main
type application struct {
DB repository.DatabaseRepo
}
func main() {
app := application{}
conn, err := app.connectToDB()
if err != nil {
log.Fatal("Failed to connect to PostgreSQL:", err)
}
defer func() {
conn.Close(context.Background())
}()
app.DB = &dbrepo.PostgresDBRepo{DB: conn}
// 将app.DB传递给routes函数进行依赖注入
mux := routes.Routes(app.DB)
package repository
type DatabaseRepo interface {
Connection() *pgx.Conn
GetCountByUsername(ctx context.Context, username string) (int, error)
}
routes.go
package routes
func Routes(app repository.DatabaseRepo) http.Handler {
mux := chi.NewRouter()
signUpH := user.New(app)
mux.Post("/signup", utils.MakeHTTPHandler(signUpH.SignUp))
}
SignUp.go
代码在调用数据库的这一行失败了。我在setup_test.go
的第4点中设置了模拟数据库。我得到的错误消息是"panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation ...]"。
package user
type application struct {
DB repository.DatabaseRepo
}
// 依赖注入Repository(数据库)
func New(app repository.DatabaseRepo) *application {
return &application{DB: app}
}
func (app application) SignUp(w http.ResponseWriter, req *http.Request) error {
// 其他逻辑
// 当我运行`go run .`时,它打印出的是*dbrepo.PostgresDBRepo
// 当我运行`go test -v ./...`时,它打印出的是<nil>
// 但预期类型应该是*dbrepo.TestDBRepo
fmt.Printf("app.DB的类型:%T\n", app.DB)
// 在单元测试中的这一行失败了
userCount, err := app.DB.GetCountByUsername(ctx, Username)
// 其他逻辑
}
setup_test.go
package main
var app application
func TestMain(m *testing.M) {
app.DB = &dbrepo.TestDBRepo{}
fmt.Printf("app.DB的类型:%T\n", app.DB) // 输出类型是*dbrepo.TestDBRepo
os.Exit(m.Run())
}
我看到许多类似的模拟数据库的单元测试使用这种方法,但它们通常在同一个main包中进行,如果你有嵌套的文件夹和包,就不会出现这个问题。
接下来我可以尝试什么?
英文:
I am creating a mock database with Golang interfaces to test my handler function. However, I don't seem to be performing the dependency injection correctly in my unit testing environment. I have created a setup_test.go
file to set up my mock database environment. In the code snippets below, I will go over the flow of how my dependency injection works.
main.go
package main
type application struct {
DB repository.DatabaseRepo
}
func main() {
app := application{}
conn, err := app.connectToDB()
if err != nil {
log.Fatal("Failed to connect to PostgreSQL:", err)
}
defer func() {
conn.Close(context.Background())
}()
app.DB = &dbrepo.PostgresDBRepo{DB: conn}
// Passing app.DB to routes function for DI
mux := routes.Routes(app.DB)
package repository
type DatabaseRepo interface {
Connection() *pgx.Conn
GetCountByUsername(ctx context.Context, username string) (int, error)
}
routes.go
package routes
func Routes(app repository.DatabaseRepo) http.Handler {
mux := chi.NewRouter()
signUpH := user.New(app)
mux.Post("/signup", utils.MakeHTTPHandler(signUpH.SignUp))
}
SignUp.go
<br>
The code fails at this line which is calling the database. I have set up my mock database in point 4 insetup_test.go
. This is the error message I am getting "panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation ...]".
package user
type application struct {
DB repository.DatabaseRepo
}
// Dependency Injection of Repository (Database)
func New(app repository.DatabaseRepo) *application {
return &application{DB: app}
}
func (app application) SignUp(w http.ResponseWriter, req *http.Request) error {
// some other logic
// When I run `go run .`, this prints out to be *dbrepo.PostgresDBRepo
// When I run `go test -v ./...`, this prints out to be <nil>
// but the expected type should be *dbrepo.TestDBRepo
fmt.Printf("Type of app.DB: %T\n", app.DB)
// fails on this line in unit testing
userCount, err := app.DB.GetCountByUsername(ctx, Username)
// some other logic
}
setup_test.go
package main
var app application
func TestMain(m *testing.M) {
app.DB = &dbrepo.TestDBRepo{}
fmt.Printf("Type of app.DB: %T\n", app.DB) // output type is *dbrepo.TestDBRepo
os.Exit(m.Run())
}
I have seen many unit testing for similar mock database using this approach but they usually do it within the same package main which will not have this issue if you have nested folders and packages like mine.
What can I try next?
答案1
得分: 0
似乎解决这个问题的唯一方法是在依赖于这个测试环境(在我的情况下是模拟数据库)的包中创建多个TestMain,正如https://groups.google.com/g/golang-nuts/c/SxEkZhWl3QA中所述。也许在将来,Golang会将这个问题纳入考虑,使得TestMain可以集成到不同的包中。
英文:
(Posted answer on behalf of the question author to move it to the answers section).
It seems like the only way to solve this issue is to create multiple TestMain in packages that rely on this test environment (in my case, the mock database) as stated in https://groups.google.com/g/golang-nuts/c/SxEkZhWl3QA. Maybe in future this concern will be added into Golang where TestMain can be integrated to different packages.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论