I have never done testing, and I have 5 end points which have methods such as GET, POST, and DELETE to test. I wrote test cases using the go's in built testing package. I'm worried that I'm missing some cases which are not striking to my mind. For example: I have an end point which goes like this:
a.Router.HandleFunc("/1/sig/id/{id:[0-9]+}", a.sigHandler).Methods("GET", "POST", "DELETE")
And the Test case goes like this:
func TestSigHandler(t *testing.T){
test_cases := []string{"2021205"}
// GET Testing
for _, method := range test_cases{
usersUrl = fmt.Sprintf("%s/1/sig/id/%s", server.URL, method) //Grab the address for the API endpoint
request, err := http.NewRequest("GET", usersUrl, nil)
res, err := http.DefaultClient.Do(request)
if err != nil {
t.Error(err) //Something is wrong while sending request
}
if res.StatusCode != 200 {
t.Errorf("Page not found : ", res.StatusCode) //Uh-oh this means our test failed
}
}
// POST Testing
sig := []byte( `{
"raw": "a new sig"
}`)
usersUrl = fmt.Sprintf("%s/1/sig/id/2021205", server.URL) //Grab the address for the API endpoint
request, err := http.NewRequest("POST", usersUrl, bytes.NewBuffer(sig))
if err != nil{
t.Error(err)
}
request.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(request)
if err != nil {
t.Error(err) //Something is wrong while sending request
}
if res.StatusCode != 200 {
t.Errorf(" Internal Server Error: ", res.StatusCode) //Uh-oh this means our test failed
}
// DELETE Testing
sigs_delete_cases := []string{ "1000345"}
for _, sig_to_be_deleted := range sigs_delete_cases{
usersUrl = fmt.Sprintf("%s/1/sig/id/%s", server.URL, sig_to_be_deleted) //Grab the address for the API endpoint
request, err := http.NewRequest("DELETE", usersUrl, nil)
res, err := http.DefaultClient.Do(request)
if err != nil {
t.Error(err) //Something is wrong while sending request
}
if res.StatusCode != 200 {
t.Errorf("Tried to delete a reserved Id : ", res.StatusCode) //Uh-oh this means our test failed
}
}
}
The problem is that, most of my test cases follow similar pattern where I post data in different formats and checking the response codes. I strongly feel like I'm missing something that will break my API when I push it to prod. I need some insight on testing these routes so that I can be confident to push the api to prod.
And my main test function goes like this:
func TestMain(m *testing.M) {
server = httptest.NewServer(a.InitializeRouter())
a.InitializeDB(fmt.Sprintf("postgres://****:****@localhost/db?sslmode=disable", os.Getenv("POSTGRES_URL")))
code := m.Run()
if code == 0 {
fmt.Println("Success!")
} else {
fmt.Println("One or more Test Cases have failed! Please use go test -v for more details")
}
os.Exit(code)
}
1 Answer 1
Using the tips of the justforfunc #16 video, you could make your tests using a table (tt
= testing table) and then iterate on it (tc
= test case).
Your test could then look like this:
func TestSigHandler(t *testing.T) {
jsonHeaders := map[string]string{"Content-Type": "application/json"}
tt := []struct {
name string
method string
uri string
payload []byte
headers map[string]string
}{
{"get item", "GET", "/1/sig/id/2021205", nil, nil},
{"post new item", "POST", "/1/sig/id/2021205", []byte(`{"raw": "a new sig"}`), jsonHeaders},
{"delete item", "DELETE", "/1/sig/id/1000345", nil, nil},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
var payload io.Reader
if tc.payload != nil {
payload = bytes.NewBuffer(tc.payload)
}
req, err := http.NewRequest(tc.method, server.URL+tc.uri, payload)
if err != nil {
t.Fatalf("could not create request: %v", err)
}
for key, value := range tc.headers {
req.Header.Set(key, value)
}
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("could not send request: %v", err)
}
if res.StatusCode != http.StatusOK {
t.Fatalf("expected status OK; got %v", res.Status)
}
})
}
}
Looking at your TestMain
, I have the feeling that you are doing only integration tests (from the request to the database).
You should split you tests to the individual layers (the current one if for routing: it could use a mocked DB).
With this approach, the TestMain
could be deleted (do only the setup that is necessary for each test).
a
? (Is suppose that you use a library ?) \$\endgroup\$