1
\$\begingroup\$

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)
}
asked Jul 24, 2017 at 17:33
\$\endgroup\$
4
  • 1
    \$\begingroup\$ Could be interesting for you: youtu.be/hVFEV-ieeew (was published yesterday) \$\endgroup\$ Commented Jul 25, 2017 at 7:58
  • \$\begingroup\$ What is a ? (Is suppose that you use a library ?) \$\endgroup\$ Commented Jul 25, 2017 at 8:02
  • \$\begingroup\$ @oliverpool a is the instance for the struct 'App' in the main.go where I'm initializing the router and db instances. \$\endgroup\$ Commented Jul 25, 2017 at 16:38
  • \$\begingroup\$ @oliverpool Great! \$\endgroup\$ Commented Jul 25, 2017 at 16:40

1 Answer 1

2
\$\begingroup\$

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

answered Jul 26, 2017 at 7:45
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.