API Testing
Melakukan tes seluruh endpoint yang dibuat.
Buat file controllers/tests/userstest.go untuk menghandle pengesan API users
package tests
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
)
//Users : struct for set Users Dependency Injection
type Users struct {
App http.Handler
}
//List : http handler for returning list of users
func (u *Users) List(t *testing.T) {
req := httptest.NewRequest("GET", "/users", nil)
req.Header.Set("Content-Type", "application/json")
resp := httptest.NewRecorder()
u.App.ServeHTTP(resp, req)
if resp.Code != http.StatusOK {
t.Fatalf("getting: expected status code %v, got %v", http.StatusOK, resp.Code)
}
var list map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&list); err != nil {
t.Fatalf("decoding: %s", err)
}
want := map[string]interface{}{
"status_code": string("REBEL-200"),
"status_message": string("OK"),
"data": []interface{}{
map[string]interface{}{
"id": float64(1),
"email": string("admin@admin.com"),
"is_active": bool(true),
},
},
}
if diff := cmp.Diff(want, list); diff != "" {
t.Fatalf("Response did not match expected. Diff:\n%s", diff)
}
}
//Crud : http handler for users crud
func (u *Users) Crud(t *testing.T) {
created := u.Create(t)
id := created["data"].(map[string]interface{})["id"].(float64)
u.View(t, id)
u.Update(t, id)
u.Delete(t, id)
}
//Create : http handler for create new user
func (u *Users) Create(t *testing.T) map[string]interface{} {
var created map[string]interface{}
jsonBody := `
{
"username": "peterpan",
"email": "peterpan@gmail.com",
"password": "1234",
"re_password": "1234",
"is_active": true
}
`
body := strings.NewReader(jsonBody)
req := httptest.NewRequest("POST", "/users", body)
req.Header.Set("Content-Type", "application/json")
resp := httptest.NewRecorder()
u.App.ServeHTTP(resp, req)
if http.StatusCreated != resp.Code {
t.Fatalf("posting: expected status code %v, got %v", http.StatusCreated, resp.Code)
}
if err := json.NewDecoder(resp.Body).Decode(&created); err != nil {
t.Fatalf("decoding: %s", err)
}
c := created["data"].(map[string]interface{})
if c["id"] == "" || c["id"] == nil {
t.Fatal("expected non-empty product id")
}
want := map[string]interface{}{
"status_code": "REBEL-200",
"status_message": "OK",
"data": map[string]interface{}{
"id": c["id"],
"email": "peterpan@gmail.com",
"is_active": false,
},
}
if diff := cmp.Diff(want, created); diff != "" {
t.Fatalf("Response did not match expected. Diff:\n%s", diff)
}
return created
}
//View : http handler for retrieve user by id
func (u *Users) View(t *testing.T, id float64) {
req := httptest.NewRequest("GET", "/users/"+fmt.Sprintf("%d", int(id)), nil)
req.Header.Set("Content-Type", "application/json")
resp := httptest.NewRecorder()
u.App.ServeHTTP(resp, req)
if http.StatusOK != resp.Code {
t.Fatalf("retrieving: expected status code %v, got %v", http.StatusOK, resp.Code)
}
var fetched map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&fetched); err != nil {
t.Fatalf("decoding: %s", err)
}
want := map[string]interface{}{
"status_code": "REBEL-200",
"status_message": "OK",
"data": map[string]interface{}{
"id": id,
"email": "peterpan@gmail.com",
"is_active": false,
},
}
// Fetched product should match the one we created.
if diff := cmp.Diff(want, fetched); diff != "" {
t.Fatalf("Retrieved user should match created. Diff:\n%s", diff)
}
}
//Update : http handler for update user by id
func (u *Users) Update(t *testing.T, id float64) {
var updated map[string]interface{}
jsonBody := `
{
"id": %s,
"is_active": "true"
}
`
body := strings.NewReader(fmt.Sprintf(jsonBody, fmt.Sprintf("%d", int(id))))
req := httptest.NewRequest("PUT", "/users/"+fmt.Sprintf("%d", int(id)), body)
req.Header.Set("Content-Type", "application/json")
resp := httptest.NewRecorder()
u.App.ServeHTTP(resp, req)
if http.StatusOK != resp.Code {
t.Fatalf("posting: expected status code %v, got %v", http.StatusOK, resp.Code)
}
if err := json.NewDecoder(resp.Body).Decode(&updated); err != nil {
t.Fatalf("decoding: %s", err)
}
want := map[string]interface{}{
"status_code": "REBEL-200",
"status_message": "OK",
"data": map[string]interface{}{
"id": id,
"email": "peterpan@gmail.com",
"is_active": true,
},
}
if diff := cmp.Diff(want, updated); diff != "" {
t.Fatalf("Response did not match expected. Diff:\n%s", diff)
}
}
//Delete : http handler for delete user by id
func (u *Users) Delete(t *testing.T, id float64) {
req := httptest.NewRequest("DELETE", "/users/"+fmt.Sprintf("%d", int(id)), nil)
req.Header.Set("Content-Type", "application/json")
resp := httptest.NewRecorder()
u.App.ServeHTTP(resp, req)
if http.StatusNoContent != resp.Code {
t.Fatalf("retrieving: expected status code %v, got %v", http.StatusNoContent, resp.Code)
}
var deleted map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&deleted); err != nil {
t.Fatalf("decoding: %s", err)
}
want := map[string]interface{}{
"status_code": "REBEL-200",
"status_message": "OK",
"data": nil,
}
// Fetched product should match the one we created.
if diff := cmp.Diff(want, deleted); diff != "" {
t.Fatalf("Response did not match expected. Diff:\n%s", diff)
}
}
Buat file tests/main_test.go
package tests
import (
apiTest "essentials/controllers/tests"
"essentials/routing"
"essentials/schema"
"log"
"os"
"testing"
_ "github.com/go-sql-driver/mysql"
)
func TestMain(t *testing.T) {
db, teardown := NewUnit(t)
defer teardown()
if err := schema.Seed(db); err != nil {
t.Fatal(err)
}
log := log.New(os.Stderr, "TEST : ", log.LstdFlags|log.Lmicroseconds|log.Lshortfile)
// api test for users
{
users := apiTest.Users{App: routing.API(db, log)}
t.Run("APiUsersList", users.List)
t.Run("APiUsersCrud", users.Crud)
}
}
go test -v essentials/tests -run TestMain
Last updated