Skip to content

Commit 0394d40

Browse files
committed
fix test mock
1 parent 7a677fa commit 0394d40

File tree

2 files changed

+60
-36
lines changed

2 files changed

+60
-36
lines changed

internal/handlers/category_handler_test.go

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,13 @@ func TestCategoryHandler_GetCategory(t *testing.T) {
135135
categoryID: "not-a-uuid",
136136
mockReturn: nil, // Mock won't be called
137137
mockError: nil,
138-
expectedStatus: http.StatusBadRequest,
139-
expectedBody: `{"error":"invalid category ID format"}`,
138+
expectedStatus: http.StatusNotFound, // <<< CORRECTION: Expect 404 from router
139+
expectedBody: "404 page not found", // <<< CORRECTION: Expect router's 404 message
140140
},
141141
{
142142
name: "Failure - Repository Error",
143143
categoryID: testID.String(),
144-
mockReturn: nil,
144+
mockReturn: nil, // <<< CORRECTION: Ensure mock returns nil object on error
145145
mockError: errors.New("db error"),
146146
expectedStatus: http.StatusInternalServerError,
147147
expectedBody: `{"error":"failed to retrieve category"}`,
@@ -150,10 +150,11 @@ func TestCategoryHandler_GetCategory(t *testing.T) {
150150

151151
for _, tc := range tests {
152152
t.Run(tc.name, func(t *testing.T) {
153-
// Setup mock expectation only if the UUID is valid and repo expected to be called
153+
// Setup mock expectation only if the UUID is valid
154154
if tc.categoryID != "not-a-uuid" {
155155
parsedID, _ := uuid.Parse(tc.categoryID)
156-
mockRepo.On("FindByID", mock.Anything, parsedID).Return(tc.mockReturn, tc.mockError).Maybe()
156+
// Use Once() unless mock isn't expected to be called
157+
mockRepo.On("FindByID", mock.Anything, parsedID).Return(tc.mockReturn, tc.mockError).Once()
157158
}
158159

159160
req := httptest.NewRequest(http.MethodGet, "/api/categories/"+tc.categoryID, nil)
@@ -163,7 +164,7 @@ func TestCategoryHandler_GetCategory(t *testing.T) {
163164

164165
assert.Equal(t, tc.expectedStatus, rr.Code)
165166
assert.Contains(t, rr.Body.String(), tc.expectedBody)
166-
mockRepo.AssertExpectations(t) // Maybe() allows call not to happen for invalid UUID test
167+
mockRepo.AssertExpectations(t)
167168
})
168169
}
169170
}
@@ -245,34 +246,38 @@ func TestCategoryHandler_CreateCategory(t *testing.T) {
245246
mockUserReturn: nil, // Won't be called
246247
mockUserErr: nil,
247248
mockCreateErr: nil,
248-
expectedStatus: http.StatusUnauthorized, // Expect unauthorized if no token provided
249-
expectedBody: `{"error":"authorization token required"}`,
249+
expectedStatus: http.StatusUnauthorized, // Expect unauthorized if no token provided
250+
expectedBody: `{"error":"authorization header required"}`, // <<< CORRECTION: Actual middleware message
250251
},
251252
}
252253

253254
for _, tc := range tests {
254255
t.Run(tc.name, func(t *testing.T) {
255256
// Mock middleware user check (only if token is expected)
256257
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody == `{"error":"user associated with token not found"}` {
257-
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Maybe()
258+
// Use Once() for middleware mock
259+
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Once()
258260
}
259261

260262
// Mock category repo create (only if middleware check passes and validation passes)
261263
if tc.mockUserErr == nil && tc.expectedStatus != http.StatusBadRequest && tc.expectedStatus != http.StatusUnauthorized {
262264
mockCategoryRepo.On("Create", mock.Anything, mock.AnythingOfType("*models.Category")).
263265
Return(func(ctx context.Context, c *models.Category) *models.Category {
266+
if tc.mockCreateErr != nil { // <<< CORRECTION: Return nil if error
267+
return nil
268+
}
264269
// Simulate DB assigning ID and timestamps
265270
c.ID = uuid.New()
266271
c.CreatedAt = time.Now()
267272
c.UpdatedAt = c.CreatedAt
268273
return c
269-
}, tc.mockCreateErr).Maybe()
274+
}, tc.mockCreateErr).Once() // <<< CORRECTION: Use Once()
270275
}
271276

272277
req := httptest.NewRequest(http.MethodPost, "/api/categories", strings.NewReader(tc.body))
273278
req.Header.Set("Content-Type", "application/json")
274279
// Only add token if the test case expects it (i.e., not the 'No Auth Token' case)
275-
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization token required"}` {
280+
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization header required"}` {
276281
req.Header.Set("Authorization", "Bearer "+testToken)
277282
}
278283

@@ -319,11 +324,11 @@ func TestCategoryHandler_UpdateCategory(t *testing.T) {
319324
name: "Failure - Invalid UUID",
320325
categoryID: "not-a-uuid",
321326
body: `{"name":"Update Attempt"}`,
322-
mockUserReturn: &models.User{ID: testUserID}, // Middleware runs before ID parsing
327+
mockUserReturn: &models.User{ID: testUserID},
323328
mockUserErr: nil,
324-
mockUpdateErr: nil, // Update won't be called
325-
expectedStatus: http.StatusBadRequest,
326-
expectedBody: `{"error":"invalid category ID format"}`,
329+
mockUpdateErr: nil,
330+
expectedStatus: http.StatusNotFound, // <<< CORRECTION: Expect 404
331+
expectedBody: "404 page not found", // <<< CORRECTION: Expect router's 404 message
327332
},
328333
{
329334
name: "Failure - Invalid JSON",
@@ -393,32 +398,35 @@ func TestCategoryHandler_UpdateCategory(t *testing.T) {
393398
mockUserErr: nil,
394399
mockUpdateErr: nil,
395400
expectedStatus: http.StatusUnauthorized,
396-
expectedBody: `{"error":"authorization token required"}`,
401+
expectedBody: `{"error":"authorization header required"}`, // <<< CORRECTION: Actual middleware message
397402
},
398403
}
399404

400405
for _, tc := range tests {
401406
t.Run(tc.name, func(t *testing.T) {
402407
// Mock middleware user check
403408
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody == `{"error":"user associated with token not found"}` {
404-
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Maybe()
409+
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Once() // <<< CORRECTION: Use Once()
405410
}
406411

407412
// Mock category repo update (only if middleware/validation/parsing passes)
408413
if tc.categoryID != "not-a-uuid" && tc.mockUserErr == nil && tc.expectedStatus != http.StatusBadRequest && tc.expectedStatus != http.StatusUnauthorized {
409414
parsedID, _ := uuid.Parse(tc.categoryID)
410415
mockCategoryRepo.On("Update", mock.Anything, parsedID, mock.AnythingOfType("*models.Category")).
411416
Return(func(ctx context.Context, id uuid.UUID, c *models.Category) *models.Category {
417+
if tc.mockUpdateErr != nil { // <<< CORRECTION: Return nil if error
418+
return nil
419+
}
412420
// Simulate DB updating timestamps
413421
c.ID = id
414422
c.UpdatedAt = time.Now() // Actual repo only returns UpdatedAt, but mock can return full
415423
return c
416-
}, tc.mockUpdateErr).Maybe()
424+
}, tc.mockUpdateErr).Once() // <<< CORRECTION: Use Once()
417425
}
418426

419427
req := httptest.NewRequest(http.MethodPut, "/api/categories/"+tc.categoryID, strings.NewReader(tc.body))
420428
req.Header.Set("Content-Type", "application/json")
421-
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization token required"}` {
429+
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization header required"}` {
422430
req.Header.Set("Authorization", "Bearer "+testToken)
423431
}
424432

@@ -463,9 +471,9 @@ func TestCategoryHandler_DeleteCategory(t *testing.T) {
463471
categoryID: "not-a-uuid",
464472
mockUserReturn: &models.User{ID: testUserID},
465473
mockUserErr: nil,
466-
mockDeleteErr: nil, // Delete won't be called
467-
expectedStatus: http.StatusBadRequest,
468-
expectedBody: `{"error":"invalid category ID format"}`,
474+
mockDeleteErr: nil, // Delete won't be called
475+
expectedStatus: http.StatusNotFound, // <<< CORRECTION: Expect 404
476+
expectedBody: "404 page not found", // <<< CORRECTION: Expect router's 404 message
469477
},
470478
{
471479
name: "Failure - Category Not Found",
@@ -501,25 +509,25 @@ func TestCategoryHandler_DeleteCategory(t *testing.T) {
501509
mockUserErr: nil,
502510
mockDeleteErr: nil,
503511
expectedStatus: http.StatusUnauthorized,
504-
expectedBody: `{"error":"authorization token required"}`,
512+
expectedBody: `{"error":"authorization header required"}`, // <<< CORRECTION: Actual middleware message
505513
},
506514
}
507515

508516
for _, tc := range tests {
509517
t.Run(tc.name, func(t *testing.T) {
510518
// Mock middleware user check
511519
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody == `{"error":"user associated with token not found"}` {
512-
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Maybe()
520+
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Once() // <<< CORRECTION: Use Once()
513521
}
514522

515523
// Mock category repo delete (only if middleware/parsing passes)
516524
if tc.categoryID != "not-a-uuid" && tc.mockUserErr == nil && tc.expectedStatus != http.StatusBadRequest && tc.expectedStatus != http.StatusUnauthorized {
517525
parsedID, _ := uuid.Parse(tc.categoryID)
518-
mockCategoryRepo.On("Delete", mock.Anything, parsedID).Return(tc.mockDeleteErr).Maybe()
526+
mockCategoryRepo.On("Delete", mock.Anything, parsedID).Return(tc.mockDeleteErr).Once() // <<< CORRECTION: Use Once()
519527
}
520528

521529
req := httptest.NewRequest(http.MethodDelete, "/api/categories/"+tc.categoryID, nil)
522-
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization token required"}` {
530+
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization header required"}` {
523531
req.Header.Set("Authorization", "Bearer "+testToken)
524532
}
525533

internal/handlers/product_handler_test.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ func TestProductHandler_GetProduct(t *testing.T) {
137137
productID: "not-a-uuid",
138138
mockReturn: nil, // Mock won't be called
139139
mockError: nil,
140-
expectedStatus: http.StatusBadRequest,
141-
expectedBody: `{"error":"invalid product ID format"}`,
140+
expectedStatus: http.StatusNotFound,
141+
expectedBody: "404 page not found",
142142
},
143143
{
144144
name: "Failure - Repository Error",
@@ -152,10 +152,10 @@ func TestProductHandler_GetProduct(t *testing.T) {
152152

153153
for _, tc := range tests {
154154
t.Run(tc.name, func(t *testing.T) {
155-
// Setup mock expectation only if the UUID is valid and repo expected to be called
155+
// Setup mock expectation only if the UUID is valid
156156
if tc.productID != "not-a-uuid" {
157157
parsedID, _ := uuid.Parse(tc.productID)
158-
mockRepo.On("FindByID", mock.Anything, parsedID).Return(tc.mockReturn, tc.mockError).Maybe()
158+
mockRepo.On("FindByID", mock.Anything, parsedID).Return(tc.mockReturn, tc.mockError).Once()
159159
}
160160

161161
req := httptest.NewRequest(http.MethodGet, "/api/products/"+tc.productID, nil)
@@ -165,7 +165,7 @@ func TestProductHandler_GetProduct(t *testing.T) {
165165

166166
assert.Equal(t, tc.expectedStatus, rr.Code)
167167
assert.Contains(t, rr.Body.String(), tc.expectedBody)
168-
mockRepo.AssertExpectations(t) // Maybe() allows call not to happen for invalid UUID test
168+
mockRepo.AssertExpectations(t)
169169
})
170170
}
171171
}
@@ -250,28 +250,44 @@ func TestProductHandler_CreateProduct(t *testing.T) {
250250
expectedStatus: http.StatusUnauthorized,
251251
expectedBody: `{"error":"user associated with token not found"}`,
252252
},
253+
{
254+
name: "Failure - No Auth Token",
255+
body: `{"name":"No Token Product","price":50.0}`,
256+
mockUserReturn: nil,
257+
mockUserErr: nil,
258+
mockCreateErr: nil,
259+
expectedStatus: http.StatusUnauthorized,
260+
expectedBody: `{"error":"authorization header required"}`,
261+
},
253262
}
254263

255264
for _, tc := range tests {
256265
t.Run(tc.name, func(t *testing.T) {
257266
// Mock middleware user check
258-
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Maybe()
267+
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody == `{"error":"user associated with token not found"}` {
268+
mockUserRepo.On("FindByID", mock.Anything, testUserID).Return(tc.mockUserReturn, tc.mockUserErr).Once()
269+
}
259270

260-
// Mock product repo create (only if middleware check is expected to pass)
261-
if tc.mockUserErr == nil {
271+
// Mock product repo create (only if middleware check is expected to pass and validation is ok)
272+
if tc.mockUserErr == nil && tc.expectedStatus != http.StatusBadRequest && tc.expectedStatus != http.StatusUnauthorized {
262273
mockProductRepo.On("Create", mock.Anything, mock.AnythingOfType("*models.Product")).
263274
Return(func(ctx context.Context, p *models.Product) *models.Product {
275+
if tc.mockCreateErr != nil {
276+
return nil
277+
}
264278
// Simulate DB assigning ID and timestamps
265279
p.ID = uuid.New()
266280
p.CreatedAt = time.Now()
267281
p.UpdatedAt = p.CreatedAt
268282
return p
269-
}, tc.mockCreateErr).Maybe()
283+
}, tc.mockCreateErr).Once()
270284
}
271285

272286
req := httptest.NewRequest(http.MethodPost, "/api/products", strings.NewReader(tc.body))
273287
req.Header.Set("Content-Type", "application/json")
274-
req.Header.Set("Authorization", "Bearer "+testToken)
288+
if tc.expectedStatus != http.StatusUnauthorized || tc.expectedBody != `{"error":"authorization header required"}` {
289+
req.Header.Set("Authorization", "Bearer "+testToken)
290+
}
275291
rr := httptest.NewRecorder()
276292

277293
router.ServeHTTP(rr, req)

0 commit comments

Comments
 (0)