2

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.

  1. 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)
}
  1. 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))
}
  1. SignUp.go
    The code fails at this line which is calling the database. I have set up my mock database in point 4 in 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
}
  1. 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?

halfer
  • 19,824
  • 17
  • 99
  • 186
Jessica
  • 243
  • 1
  • 10
  • 1
    Hi, if you try to stick to the solution provided here, it should work for this https://stackoverflow.com/questions/75798345/golang-create-a-mock-database-with-handler-and-call-to-database-using-interfaces/75802059#comment133804432_75802059 Furthermore, writing unit tests for the `main` package is not recommended. To take advantage of the DB functionalities you can avoid using the interfaces. Just rely on the generic `sql.DB` if you don't want to use an ORM. Try to adjust the code and then let me know! – ossan Mar 27 '23 at 15:21
  • @IvanPesenti I understand but I am actually not allowed to use third party packages for mocking the database that's why I am trying to implement this interface. – Jessica Mar 27 '23 at 15:37
  • I have found out a temporary solution, that is to add a `setup_test.go` file in all the different packages that I want to test. This seems very cumbersome so if anyone has a better solution please let me know! :D – Jessica Mar 27 '23 at 16:55

1 Answers1

0

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

halfer
  • 19,824
  • 17
  • 99
  • 186
  • I have rolled back the edit on this CW post. I think its purpose was to preserve the original answer in the question author's words, but this is not necessary - it is kept [in the revision history](https://stackoverflow.com/posts/75857122/revisions). – halfer Jul 02 '23 at 17:39