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
setup_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?
(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.