Home > OS >  How to unit testing with Gorm, mux, postgresql
How to unit testing with Gorm, mux, postgresql

Time:03-29

I'm new in Go and unit test. I build a samll side projecy called "urlshortener" using Go with Gorm, mux and postgresql.

There is a qeustion annoying me after search many articles.

To make the question clean, I delete some irrelevant code like connect db, .env, etc

My code is below(main.go):

package main

type Url struct {
    ID       uint   `gorm:"primaryKey"` // used for shortUrl index
    Url      string `gorm:"unique"`     // prevent duplicate url
    ExpireAt string
    ShortUrl string
}

var db *gorm.DB
var err error


func main() {
    // gain access to database by getting .env
    ...

    // database connection string
    ...

    // make migrations to the dbif they have not already been created
    db.AutoMigrate(&Url{})

    // API routes
    router := mux.NewRouter()

    router.HandleFunc("/{id}", getURL).Methods("GET")

    router.HandleFunc("/api/v1/urls", createURL).Methods("POST")
    router.HandleFunc("/create/urls", createURLs).Methods("POST")

    // Listener
    http.ListenAndServe(":80", router)

    // close connection to db when main func finishes
    defer db.Close()
}

Now I'm building unit test for getURL function, which is a GET method to get data from my postgresql database called urlshortener and the table name is urls.

Here is getURL function code:

func getURL(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    var url Url

    err := db.Find(&url, params["id"]).Error
    if err != nil {
        w.WriteHeader(http.StatusNotFound)
    } else {
        w.WriteHeader(http.StatusOK)
        json.NewEncoder(w).Encode(url.Url)
    }
}

This is work fine with my database. See curl command below: enter image description here

I know that the unit test is not for mock data, and it aim to test a function/method is stable or not. Although I import mux and net/http for conncetion, but I think the unit test on it should be "SQL syntax". So I decide to focus on testing if gorm return the right value to the test function.

In this case, db.Find will return a *gorm.DB struct which should be exactly same with second line. (see docs enter image description here

when db.find called, mock.ExpectQuery receive it and start to compare it, so far so good.

db.Find(&url, params["id"])
mock.ExpectQuery(regexp.QuoteMeta(testQuery)).WillReturnRows(rows).WithArgs(id)

According to the testing log, it shows that when db.Find triggerd, it only excute SELECT * FROM "urls" but not I expected SELECT * FROM "urls" WHERE "urls"."id" = $1.

But when I test db.Find on local with postman and log the SQL syntax out, it can be excute properly. see pic below. enter image description here

In summary, I think the problem is the responeWriter/request I put in getURL(mockedWriter, mockedRequest) are wrong, and it leads that getURL(w http.ResponseWriter, r *http.Request) cannot work as we expect.

Please let me know if I missing anything~

Any idea or way to rewrite the code would be help, thank you!

CodePudding user response:

If you just want to test the SQL string that db.Find returns, you can use the DryRun feature (per enter image description here

  • Related