Skip to content

Commit 4c0bb39

Browse files
Test/cucumber fetch and save (#71)
* test(cucumber_fetch_and_save): add cucumber test for fetch and save * test(cucumber_fetch_and_save): fix the constroller so it doesn't return a 500 when the fetching size is too big * test(cucumber_fetch_and_save): add exception handler for constrain violation * test(cucumber_fetch_and_save): add unit test for exception handler * test(cucumber_fetch_and_save): fix the exception handling --------- Co-authored-by: Romain Vanhee <romain.vanhee@yrycom.com>
1 parent 60cda58 commit 4c0bb39

6 files changed

Lines changed: 78 additions & 25 deletions

File tree

src/main/java/com/xpeho/spring_boot_java_random_user/presentation/exceptions/GlobalExceptionHandler.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.xpeho.spring_boot_java_random_user.domain.exceptions.InvalidPaginationException;
44
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
5+
import jakarta.validation.ConstraintViolationException;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
78
import org.springframework.http.HttpStatus;
@@ -14,6 +15,16 @@
1415
public class GlobalExceptionHandler {
1516
private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
1617

18+
@ExceptionHandler(ConstraintViolationException.class)
19+
public ResponseEntity<ErrorResponse> handleConstraintViolationException(ConstraintViolationException ex) {
20+
String message = ex.getConstraintViolations().stream()
21+
.map(v -> v.getPropertyPath() + ": " + v.getMessage())
22+
.findFirst()
23+
.orElse(ex.getMessage());
24+
logger.warn("Constraint violation: {}", message);
25+
return buildErrorResponse("INVALID_PAGINATION", message, HttpStatus.BAD_REQUEST);
26+
}
27+
1728
@ExceptionHandler(InvalidPaginationException.class)
1829
public ResponseEntity<ErrorResponse> handleInvalidPaginationException(InvalidPaginationException ex) {
1930
logger.warn("Invalid pagination request: {}", ex.getMessage());

src/main/java/com/xpeho/spring_boot_java_random_user/presentation/handlers/UserHandler.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
77
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
88
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
9-
import com.xpeho.spring_boot_java_random_user.domain.exceptions.InvalidPaginationException;
109
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
1110
import com.xpeho.spring_boot_java_random_user.domain.usecases.*;
1211
import com.xpeho.spring_boot_java_random_user.presentation.controllers.UserController;
@@ -15,13 +14,15 @@
1514
import org.slf4j.LoggerFactory;
1615
import org.springframework.http.HttpStatus;
1716
import org.springframework.http.ResponseEntity;
17+
import org.springframework.validation.annotation.Validated;
1818
import org.springframework.web.bind.annotation.RequestBody;
1919
import org.springframework.web.bind.annotation.RestController;
2020

2121
import java.io.IOException;
2222
import java.util.List;
2323

2424

25+
@Validated
2526
@RestController
2627
public class UserHandler implements UserController {
2728

@@ -54,12 +55,6 @@ public UserHandler(
5455

5556
@Override
5657
public ResponseEntity<UserResponseDTO> getRandomUsers(int page, int size, UserSource source) {
57-
if (page < 1) {
58-
throw new InvalidPaginationException("Page must be greater than or equal to 1. Requested: " + page);
59-
}
60-
if (size < 1 || size > 30) {
61-
throw new InvalidPaginationException("Page size must be between 1 and 30. Requested: " + size);
62-
}
6358
try {
6459
PaginatedUsers result = fetchAndSaveRandomUsersUseCase.execute(page, size, source);
6560
UserResponseDTO response = new UserResponseDTO(
@@ -70,7 +65,7 @@ public ResponseEntity<UserResponseDTO> getRandomUsers(int page, int size, UserSo
7065
);
7166
return ResponseEntity.ok(response);
7267
} catch (IOException e) {
73-
logger.error("Error fetching random users: {}", e.getMessage(), e);
68+
logger.error("Error fetching random users", e);
7469
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
7570
}
7671
}
@@ -124,6 +119,6 @@ public void deleteUserById(int id) {
124119
}
125120

126121
private void logUserNotFound(UserNotFoundException e) {
127-
logger.warn(USER_NOT_FOUND_LOG, e.getMessage(), e);
122+
logger.warn(USER_NOT_FOUND_LOG, e);
128123
}
129124
}

src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserHandlerTest.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@
66
import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
77
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
88
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
9-
import com.xpeho.spring_boot_java_random_user.domain.exceptions.InvalidPaginationException;
109
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
1110
import com.xpeho.spring_boot_java_random_user.domain.usecases.*;
1211
import com.xpeho.spring_boot_java_random_user.presentation.handlers.UserHandler;
1312
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
1413
import org.junit.jupiter.api.BeforeEach;
1514
import org.junit.jupiter.api.DisplayName;
1615
import org.junit.jupiter.api.Test;
17-
import org.junit.jupiter.params.ParameterizedTest;
18-
import org.junit.jupiter.params.provider.CsvSource;
1916
import org.springframework.http.HttpStatus;
2017
import org.springframework.http.ResponseEntity;
2118

@@ -82,19 +79,6 @@ void shouldReturnInternalServerErrorWhenGetRandomUsersFails() throws IOException
8279
verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(page, size, UserSource.RANDOM_USER);
8380
}
8481

85-
@ParameterizedTest
86-
@CsvSource({
87-
"1, 31",
88-
"0, 10",
89-
"1, 0"
90-
})
91-
@DisplayName("Should throw InvalidPaginationException for invalid pagination inputs")
92-
void shouldThrowInvalidPaginationExceptionForInvalidPaginationInputs(int page, int size) throws IOException {
93-
assertThrows(InvalidPaginationException.class, () -> userHandler.getRandomUsers(page, size, UserSource.DUMMY));
94-
verify(fetchAndSaveRandomUsersUseCase, never()).execute(page, size, UserSource.DUMMY);
95-
}
96-
97-
9882
@Test
9983
@DisplayName("Should return 200 and user when getUserById succeeds")
10084
void shouldReturnOkWhenGetUserByIdSucceeds() {

src/test/java/com/xpeho/spring_boot_java_random_user/presentation/exceptions/GlobalExceptionHandlerTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,42 @@
33
import com.xpeho.spring_boot_java_random_user.domain.exceptions.InvalidPaginationException;
44
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
55
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
6+
import jakarta.validation.ConstraintViolation;
7+
import jakarta.validation.ConstraintViolationException;
68
import org.junit.jupiter.api.DisplayName;
79
import org.junit.jupiter.api.Test;
810
import org.springframework.http.HttpStatus;
911
import org.springframework.http.ResponseEntity;
1012
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
1113

14+
import java.util.Set;
15+
1216
import static org.junit.jupiter.api.Assertions.*;
17+
import static org.mockito.Mockito.mock;
18+
import static org.mockito.Mockito.when;
1319

1420
class GlobalExceptionHandlerTest {
1521

1622
private final GlobalExceptionHandler handler = new GlobalExceptionHandler();
1723

24+
@Test
25+
@DisplayName("Should return 400 BAD_REQUEST when ConstraintViolationException is thrown")
26+
void shouldReturnBadRequestWhenConstraintViolationException() {
27+
ConstraintViolation<?> violation = mock(ConstraintViolation.class);
28+
when(violation.getPropertyPath()).thenReturn(mock(jakarta.validation.Path.class));
29+
when(violation.getPropertyPath().toString()).thenReturn("size");
30+
when(violation.getMessage()).thenReturn("must be less than or equal to 30");
31+
32+
ConstraintViolationException ex = new ConstraintViolationException(Set.of(violation));
33+
ResponseEntity<ErrorResponse> response = handler.handleConstraintViolationException(ex);
34+
35+
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
36+
assertNotNull(response.getBody());
37+
assertEquals("INVALID_PAGINATION", response.getBody().error());
38+
assertEquals(400, response.getBody().status());
39+
assertTrue(response.getBody().message().contains("must be less than or equal to 30"));
40+
}
41+
1842
@Test
1943
@DisplayName("Should return 400 BAD_REQUEST when InvalidPaginationException is thrown")
2044
void shouldReturnBadRequestWhenInvalidPaginationException() {

src/test/java/feature/StepDefinition.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,28 @@ public void theClientCallToGetTheCreatedUser() {
7878
assertNotNull(createdUserId, "No user was created before this step");
7979
executeGet("/random-users/" + createdUserId);
8080
}
81+
82+
@When("the client call to GET \\/random-users")
83+
public void theClientCallToGetRandomUsers() {
84+
executeGet("/random-users");
85+
}
86+
87+
@When("the client call to GET \\/random-users with page {int} and size {int}")
88+
public void theClientCallToGetRandomUsersWithPageAndSize(int page, int size) {
89+
executeGet("/random-users?page=" + page + "&size=" + size);
90+
}
91+
92+
@And("the response contains a list of users")
93+
public void theResponseContainsAListOfUsers() throws Exception {
94+
JsonNode body = objectMapper.readTree(latestResponse.getBody());
95+
assertNotNull(body.get("data"));
96+
assertTrue(body.get("data").isArray());
97+
}
98+
99+
@And("the response contains {int} users")
100+
public void theResponseContainsUsers(int expectedSize) throws Exception {
101+
JsonNode body = objectMapper.readTree(latestResponse.getBody());
102+
assertNotNull(body.get("data"));
103+
assertEquals(expectedSize, body.get("data").size());
104+
}
81105
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
Feature: GET /random-users endpoint
2+
3+
Scenario: Fetch random users with default parameters
4+
When the client call to GET /random-users
5+
Then the response status should be 200
6+
And the response contains a list of users
7+
8+
Scenario: Fetch random users with custom page and size
9+
When the client call to GET /random-users with page 1 and size 5
10+
Then the response status should be 200
11+
And the response contains 5 users
12+
13+
Scenario: Fetch random users with size above maximum
14+
When the client call to GET /random-users with page 1 and size 31
15+
Then the response status should be 400

0 commit comments

Comments
 (0)