github.com/lovung/GoCleanArchitecture@v0.0.0-20210302152432-50d91fd29f9f/app/internal/interface/restful/handler/auth_handler_test.go (about) 1 package handler 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "net/http" 8 "net/http/httptest" 9 "reflect" 10 "testing" 11 12 "github.com/gin-gonic/gin" 13 "github.com/golang/mock/gomock" 14 "github.com/google/go-cmp/cmp" 15 "github.com/lovung/GoCleanArchitecture/app/internal/interface/restful/middleware" 16 "github.com/lovung/GoCleanArchitecture/app/internal/interface/restful/presenter" 17 "github.com/lovung/GoCleanArchitecture/app/internal/usecase" 18 "github.com/lovung/GoCleanArchitecture/app/internal/usecase/dto" 19 "github.com/lovung/GoCleanArchitecture/app/internal/usecase/mockusecase" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestNewAuthHandler(t *testing.T) { 24 type args struct { 25 userUseCase usecase.UserUseCase 26 } 27 t.Parallel() 28 mockCtrl := gomock.NewController(t) 29 defer mockCtrl.Finish() 30 mUserUseCase := mockusecase.NewMockUserUseCase(mockCtrl) 31 32 testCases := []struct { 33 name string 34 args args 35 want AuthHandler 36 }{ 37 { 38 args: args{ 39 userUseCase: mUserUseCase, 40 }, 41 want: AuthHandler{ 42 BaseHandler: BaseHandler{}, 43 userUseCase: mUserUseCase, 44 }, 45 }, 46 } 47 for _, tt := range testCases { 48 t.Run(tt.name, func(t *testing.T) { 49 if got := NewAuthHandler(tt.args.userUseCase); !reflect.DeepEqual(got, tt.want) { 50 t.Errorf("NewAuthHandler() = %v, want %v", got, tt.want) 51 } 52 }) 53 } 54 } 55 56 func TestAuthHandler_Register(t *testing.T) { 57 type fields struct { 58 BaseHandler BaseHandler 59 userUseCase usecase.UserUseCase 60 } 61 type args struct { 62 // ctx *gin.Context 63 req presenter.RegisterRequest 64 } 65 type wants struct { 66 httpCode int 67 body interface{} 68 } 69 t.Parallel() 70 mockCtrl := gomock.NewController(t) 71 defer mockCtrl.Finish() 72 mUserUseCase := mockusecase.NewMockUserUseCase(mockCtrl) 73 _fields := fields{ 74 BaseHandler: BaseHandler{}, 75 userUseCase: mUserUseCase, 76 } 77 78 runFunc := func(t *testing.T, fields fields, args args, w wants) { 79 hdl := &AuthHandler{ 80 BaseHandler: fields.BaseHandler, 81 userUseCase: fields.userUseCase, 82 } 83 // Switch to test mode so you don't get such noisy output 84 gin.SetMode(gin.TestMode) 85 86 // Create a response recorder so you can inspect the response 87 resp := httptest.NewRecorder() 88 r := gin.Default() 89 // Setup your router, just like you did in your main function, and 90 // register your routes 91 r.Use(middleware.JSONWriterMiddleware) 92 r.POST("/register", hdl.Register) 93 // Create the mock request you'd like to test. Make sure the second argument 94 // here is the same as one of the routes you defined in the router setup 95 // block! 96 body, err := json.Marshal(args.req) 97 assert.NoError(t, err) 98 req, err := http.NewRequest(http.MethodPost, "/register", bytes.NewReader(body)) 99 assert.NoError(t, err) 100 101 // Perform the request 102 r.ServeHTTP(resp, req) 103 assert.Equal(t, w.httpCode, resp.Code) 104 if diff := cmp.Diff(w.body, resp.Body.String()); diff != "" { 105 t.Errorf("Diff body = %v", diff) 106 assert.Equal(t, w.body, resp.Body.String()) 107 } 108 } 109 t.Run("#1: Error when binding", func(t *testing.T) { 110 runFunc(t, _fields, 111 args{ 112 req: presenter.RegisterRequest{ 113 Username: "username", 114 }, 115 }, 116 wants{ 117 httpCode: 400, 118 body: "{\"meta\":{\"code\":400,\"message\":\"error when binding the request\"},\"errors\":[{\"code\":422,\"detail\":\"Key: 'RegisterRequest.Password' Error:Field validation for 'Password' failed on the 'required' tag\",\"source\":{\"pointer\":\"RegisterRequest.Password\",\"parameter\":\"Password\"}}]}", 119 }) 120 }) 121 t.Run("#2: Error when binding username", func(t *testing.T) { 122 runFunc(t, _fields, 123 args{ 124 req: presenter.RegisterRequest{ 125 Password: "password", 126 }, 127 }, 128 wants{ 129 httpCode: 400, 130 body: "{\"meta\":{\"code\":400,\"message\":\"error when binding the request\"},\"errors\":[{\"code\":422,\"detail\":\"Key: 'RegisterRequest.Username' Error:Field validation for 'Username' failed on the 'required' tag\",\"source\":{\"pointer\":\"RegisterRequest.Username\",\"parameter\":\"Username\"}}]}", 131 }) 132 }) 133 t.Run("#3: Call use case got error", func(t *testing.T) { 134 mUserUseCase.EXPECT().Create(gomock.Any(), dto.CreateUserRequest{ 135 Password: "password", 136 Username: "username", 137 }).Return(dto.OneUserResponse{}, errors.New("error")) 138 runFunc(t, _fields, 139 args{ 140 req: presenter.RegisterRequest{ 141 Username: "username", 142 Password: "password", 143 }, 144 }, 145 // TODO: Update wants when implementing the JSONWriterMiddleware 146 // to handle the App Error (error from business logic) 147 wants{ 148 httpCode: 204, 149 body: "", 150 }) 151 }) 152 t.Run("#4: Success", func(t *testing.T) { 153 mUserUseCase.EXPECT().Create(gomock.Any(), dto.CreateUserRequest{ 154 Password: "password", 155 Username: "username", 156 }).Return(dto.OneUserResponse{ 157 ID: "id", 158 Username: "username", 159 }, nil) 160 runFunc(t, _fields, 161 args{ 162 req: presenter.RegisterRequest{ 163 Username: "username", 164 Password: "password", 165 }, 166 }, 167 wants{ 168 httpCode: 201, 169 body: "{\"meta\":{\"code\":201},\"data\":{\"id\":\"id\",\"username\":\"username\"}}", 170 }) 171 }) 172 } 173 174 // func TestAuthHandler_RegisterWithTransaction(t *testing.T) { 175 // type fields struct { 176 // BaseHandler BaseHandler 177 // userUseCase usecase.UserUseCase 178 // } 179 // type args struct { 180 // // ctx *gin.Context 181 // req presenter.RegisterRequest 182 // } 183 // type wants struct { 184 // httpCode int 185 // body interface{} 186 // } 187 // t.Parallel() 188 // mockCtrl := gomock.NewController(t) 189 // defer mockCtrl.Finish() 190 // mUserUseCase := mockusecase.NewMockUserUseCase(mockCtrl) 191 // mTransactionManager := mocktrans.NewMockManager(mockCtrl) 192 // gDB, _, err := tests.OpenDBConnection() 193 // logger.Init(true) 194 // assert.NoError(t, err) 195 // _fields := fields{ 196 // BaseHandler: BaseHandler{}, 197 // userUseCase: mUserUseCase, 198 // } 199 200 // runFunc := func(t *testing.T, fields fields, args args, w wants) { 201 // hdl := &AuthHandler{ 202 // BaseHandler: fields.BaseHandler, 203 // userUseCase: fields.userUseCase, 204 // } 205 // txnMw := middleware.NewTransactionMiddleware(mTransactionManager) 206 // // Switch to test mode so you don't get such noisy output 207 // gin.SetMode(gin.TestMode) 208 209 // // Create a response recorder so you can inspect the response 210 // resp := httptest.NewRecorder() 211 // ctx, r := gin.CreateTestContext(resp) 212 // // Setup your router, just like you did in your main function, and 213 // // register your routes 214 // r.Use(middleware.JSONWriterMiddleware) 215 // r.Use(txnMw.StartRequest) 216 // r.Use(txnMw.EndRequest) 217 // r.POST("/register", hdl.Register) 218 // // Create the mock request you'd like to test. Make sure the second argument 219 // // here is the same as one of the routes you defined in the router setup 220 // // block! 221 // body, err := json.Marshal(args.req) 222 // assert.NoError(t, err) 223 // req, err := http.NewRequest(http.MethodPost, "/register", bytes.NewReader(body)) 224 // assert.NoError(t, err) 225 226 // tx := gDB.Begin() 227 // newCtx := appctx.SetValue(ctx.Request.Context(), appctx.TransactionContextKey, tx) 228 229 // mTransactionManager.EXPECT().TxnBegin(gomock.Any()).Return(newCtx) 230 // mTransactionManager.EXPECT().TxnRollback(gomock.Any()).Return(nil) 231 // // Perform the request 232 // r.ServeHTTP(resp, req) 233 // assert.Equal(t, w.httpCode, resp.Code) 234 // if diff := cmp.Diff(w.body, resp.Body.String()); diff != "" { 235 // t.Errorf("Diff body = %v", diff) 236 // assert.Equal(t, w.body, resp.Body.String()) 237 // } 238 // } 239 // t.Run("#1: Error when binding", func(t *testing.T) { 240 // runFunc(t, _fields, 241 // args{ 242 // req: presenter.RegisterRequest{ 243 // Username: "username", 244 // }, 245 // }, 246 // wants{ 247 // httpCode: 400, 248 // body: "{\"meta\":{\"code\":400,\"message\":\"error when binding the request\"},\"errors\":[{\"code\":422,\"detail\":\"Key: 'RegisterRequest.Password' Error:Field validation for 'Password' failed on the 'required' tag\",\"source\":{\"pointer\":\"RegisterRequest.Password\",\"parameter\":\"Password\"}}]}", 249 // }) 250 // }) 251 // t.Run("#2: Error when binding username", func(t *testing.T) { 252 // ctx := context.Background() 253 // tx := gDB.Begin() 254 // ctx = appctx.SetValue(ctx, appctx.TransactionContextKey, tx) 255 // mTransactionManager.EXPECT().TxnBegin(gomock.Any()).Return(ctx) 256 // mTransactionManager.EXPECT().TxnRollback(gomock.Any()).Return(nil) 257 // runFunc(t, _fields, 258 // args{ 259 // req: presenter.RegisterRequest{ 260 // Password: "password", 261 // }, 262 // }, 263 // wants{ 264 // httpCode: 400, 265 // body: "{\"meta\":{\"code\":400,\"message\":\"error when binding the request\"},\"errors\":[{\"code\":422,\"detail\":\"Key: 'RegisterRequest.Username' Error:Field validation for 'Username' failed on the 'required' tag\",\"source\":{\"pointer\":\"RegisterRequest.Username\",\"parameter\":\"Username\"}}]}", 266 // }) 267 // }) 268 // t.Run("#3: Call use case got error", func(t *testing.T) { 269 // ctx := context.Background() 270 // tx := gDB.Begin() 271 // ctx = appctx.SetValue(ctx, appctx.TransactionContextKey, tx) 272 // mTransactionManager.EXPECT().TxnBegin(gomock.Any()).Return(ctx) 273 // mTransactionManager.EXPECT().TxnRollback(gomock.Any()).Return(nil) 274 // mUserUseCase.EXPECT().Create(gomock.Any(), dto.CreateUserRequest{ 275 // Password: "password", 276 // Username: "username", 277 // }).Return(dto.OneUserResponse{}, errors.New("error")) 278 // runFunc(t, _fields, 279 // args{ 280 // req: presenter.RegisterRequest{ 281 // Username: "username", 282 // Password: "password", 283 // }, 284 // }, 285 // // TODO: Update wants when implementing the JSONWriterMiddleware 286 // // to handle the App Error (error from business logic) 287 // wants{ 288 // httpCode: 204, 289 // body: "", 290 // }) 291 // }) 292 // t.Run("#4: Success", func(t *testing.T) { 293 // ctx := context.Background() 294 // tx := gDB.Begin() 295 // ctx = appctx.SetValue(ctx, appctx.TransactionContextKey, tx) 296 // mTransactionManager.EXPECT().TxnBegin(gomock.Any()).Return(ctx) 297 // mTransactionManager.EXPECT().TxnCommit(gomock.Any()).Return(nil) 298 // mTransactionManager.EXPECT().GetTxn(gomock.Any()).Return(tx) 299 // mUserUseCase.EXPECT().Create(gomock.Any(), dto.CreateUserRequest{ 300 // Password: "password", 301 // Username: "username", 302 // }).Return(dto.OneUserResponse{ 303 // ID: "id", 304 // Username: "username", 305 // }, nil) 306 // runFunc(t, _fields, 307 // args{ 308 // req: presenter.RegisterRequest{ 309 // Username: "username", 310 // Password: "password", 311 // }, 312 // }, 313 // wants{ 314 // httpCode: 201, 315 // body: "{\"meta\":{\"code\":201},\"data\":{\"id\":\"id\",\"username\":\"username\"}}", 316 // }) 317 // }) 318 // }