Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
627 changes: 458 additions & 169 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.xpeho.spring_boot_java_random_user.domain.usecases;

import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
import org.springframework.stereotype.Service;

@Service
public class GetUserByIdUseCase {
private final UserService userService;

public GetUserByIdUseCase(UserService userService) {
this.userService = userService;
}

public UserEntity execute(long id) {
return userService.getById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ public UpdateRandomUserUseCase(UserService userService) {

public UserEntity execute(int id, UserRequest user) {
UserEntity existingUser = userService.getById(id)
.orElseThrow(() -> new UserNotFoundException(id));
.orElseThrow(() -> new UserNotFoundException(id));

UserEntity updatedUser = new UserEntity(
existingUser.id(),
user.gender(),
user.firstname(),
user.lastname(),
user.civility(),
user.email(),
user.phone(),
user.picture(),
user.nat()
existingUser.id(),
user.gender(),
user.firstname(),
user.lastname(),
user.civility(),
user.email(),
user.phone(),
user.picture(),
user.nat()
);

return userService.save(updatedUser);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ ResponseEntity<List<UserEntity>> getRandomUsers(
@Max(5000)
int count
);

@GetMapping("/{id}")
@Operation(
summary = "Get user by id",
description = "Given a user by id, return the user if it exists in the database",
Comment thread
MayuriXx marked this conversation as resolved.
parameters = {
@Parameter(name = "id", description = "id of the requested user")
}
Comment thread
MayuriXx marked this conversation as resolved.
)
@ApiResponse(responseCode = "200", description = "User successfully found and returned")
@ApiResponse(responseCode = "404", description = "The requested user does not exist")
@ApiResponse(responseCode = "500", description = "Internal server error")
ResponseEntity<UserEntity> getUserById(
@PathVariable
int id
);
Comment thread
MayuriXx marked this conversation as resolved.

@PutMapping("/{id}")
@Operation(
summary = "Modify a random user",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.usecases.FetchAndSaveRandomUsersUseCase;
import com.xpeho.spring_boot_java_random_user.domain.usecases.GetUserByIdUseCase;
import com.xpeho.spring_boot_java_random_user.domain.usecases.UpdateRandomUserUseCase;
import com.xpeho.spring_boot_java_random_user.presentation.controllers.UserController;
import org.slf4j.Logger;
Expand All @@ -24,13 +25,16 @@ public class UserHandler implements UserController {

private final FetchAndSaveRandomUsersUseCase fetchAndSaveRandomUsersUseCase;
private final UpdateRandomUserUseCase updateRandomUserUseCase;
private final GetUserByIdUseCase getUserByIdUseCase;

public UserHandler(
FetchAndSaveRandomUsersUseCase fetchAndSaveRandomUsersUseCase,
UpdateRandomUserUseCase updateRandomUserUseCase
UpdateRandomUserUseCase updateRandomUserUseCase,
GetUserByIdUseCase getUserByIdUseCase
) {
this.fetchAndSaveRandomUsersUseCase = fetchAndSaveRandomUsersUseCase;
this.updateRandomUserUseCase = updateRandomUserUseCase;
this.getUserByIdUseCase = getUserByIdUseCase;
}

@Override
Expand All @@ -55,4 +59,15 @@ public ResponseEntity<UserEntity> updateRandomUser(int id, UserRequest user) {
}
}

@Override
public ResponseEntity<UserEntity> getUserById(int id) {
try {
UserEntity user = getUserByIdUseCase.execute(id);
return ResponseEntity.ok(user);
} catch (UserNotFoundException e) {
logger.warn("warning: the requested user does not exist : {}", e.getMessage(), e);
Comment thread
MayuriXx marked this conversation as resolved.
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
Comment thread
MayuriXx marked this conversation as resolved.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.xpeho.spring_boot_java_random_user.domain.usecases;

import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

class GetUserByIdUseCaseTest {
private UserService userService;
private GetUserByIdUseCase useCase;

@BeforeEach
void setUp() {
userService = mock(UserService.class);
useCase = new GetUserByIdUseCase(userService);
}

@Test
@DisplayName("Should return user when user exists")
void shouldReturnUserWhenFound() {
UserEntity expected = new UserEntity(1L, "male", "John", "Doe", "Mr", "john@example.com", "0600000000", "http://pic.jpg", "FR");
when(userService.getById(1L)).thenReturn(Optional.of(expected));

UserEntity result = useCase.execute(1L);

assertEquals(expected, result);
verify(userService).getById(1L);
}

@Test
@DisplayName("Should throw UserNotFoundException when user does not exist")
void shouldThrowUserNotFoundExceptionWhenUserDoesNotExist() {
when(userService.getById(99L)).thenReturn(Optional.empty());

UserNotFoundException exception = assertThrows(
UserNotFoundException.class,
() -> useCase.execute(99L)
);

assertTrue(exception.getMessage().contains("99"));
verify(userService).getById(99L);
}

@Test
@DisplayName("Should call userService exactly once with the given id")
void shouldCallUserServiceOnce() {
UserEntity user = new UserEntity(5L, "female", "Alice", "Smith", "Ms", "alice@example.com", "0611111111", "http://pic2.jpg", "US");
when(userService.getById(5L)).thenReturn(Optional.of(user));

useCase.execute(5L);

verify(userService, times(1)).getById(5L);
verifyNoMoreInteractions(userService);
}

@Test
@DisplayName("Should not call userService with a different id")
void shouldNotCallUserServiceWithDifferentId() {
UserEntity user = new UserEntity(3L, "male", "Bob", "Brown", "Mr", "bob@example.com", "0622222222", "http://pic3.jpg", "DE");
when(userService.getById(3L)).thenReturn(Optional.of(user));

useCase.execute(3L);

verify(userService, never()).getById(42L);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.xpeho.spring_boot_java_random_user.presentation;

import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.usecases.FetchAndSaveRandomUsersUseCase;
import com.xpeho.spring_boot_java_random_user.domain.usecases.GetUserByIdUseCase;
import com.xpeho.spring_boot_java_random_user.domain.usecases.UpdateRandomUserUseCase;
import com.xpeho.spring_boot_java_random_user.presentation.handlers.UserHandler;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.io.IOException;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class UserHandlerTest {

private FetchAndSaveRandomUsersUseCase fetchAndSaveRandomUsersUseCase;
private UpdateRandomUserUseCase updateRandomUserUseCase;
private GetUserByIdUseCase getUserByIdUseCase;
private UserHandler userHandler;

@BeforeEach
void setUp() {
fetchAndSaveRandomUsersUseCase = mock(FetchAndSaveRandomUsersUseCase.class);
updateRandomUserUseCase = mock(UpdateRandomUserUseCase.class);
getUserByIdUseCase = mock(GetUserByIdUseCase.class);
userHandler = new UserHandler(fetchAndSaveRandomUsersUseCase, updateRandomUserUseCase, getUserByIdUseCase);
}

@Test
@DisplayName("Should return 200 and users when getRandomUsers succeeds")
void shouldReturnOkWhenGetRandomUsersSucceeds() throws IOException {
List<UserEntity> users = List.of(
new UserEntity(1L, "male", "John", "Doe", "Mr", "john@example.com", "0600000000", "pic.jpg", "FR")
);
when(fetchAndSaveRandomUsersUseCase.execute(2)).thenReturn(users);

ResponseEntity<List<UserEntity>> response = userHandler.getRandomUsers(2);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(users, response.getBody());
verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(2);
}

@Test
@DisplayName("Should return 500 and empty list when getRandomUsers throws IOException")
void shouldReturnInternalServerErrorWhenGetRandomUsersFails() throws IOException {
when(fetchAndSaveRandomUsersUseCase.execute(5)).thenThrow(new IOException("downstream unavailable"));

ResponseEntity<List<UserEntity>> response = userHandler.getRandomUsers(5);

assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
assertTrue(response.getBody() != null && response.getBody().isEmpty());
verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(5);
}

@Test
@DisplayName("Should return 200 and user when getUserById succeeds")
void shouldReturnOkWhenGetUserByIdSucceeds() {
UserEntity user = new UserEntity(42L, "female", "Alice", "Smith", "Ms", "alice@example.com", "0611111111", "alice.jpg", "US");
when(getUserByIdUseCase.execute(42)).thenReturn(user);

ResponseEntity<UserEntity> response = userHandler.getUserById(42);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(user, response.getBody());
verify(getUserByIdUseCase, times(1)).execute(42);
}

@Test
@DisplayName("Should return 404 when getUserById throws UserNotFoundException")
void shouldReturnNotFoundWhenGetUserByIdFails() {
when(getUserByIdUseCase.execute(99)).thenThrow(new UserNotFoundException(99));

ResponseEntity<UserEntity> response = userHandler.getUserById(99);

assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertNull(response.getBody());
verify(getUserByIdUseCase, times(1)).execute(99);
}

@Test
@DisplayName("Should return 200 and updated user when updateRandomUser succeeds")
void shouldReturnOkWhenUpdateRandomUserSucceeds() {
UserRequest request = new UserRequest("female", "Jane", "Doe", "Ms", "jane@example.com", "0622222222", "jane.jpg", "FR");
UserEntity updated = new UserEntity(7L, "female", "Jane", "Doe", "Ms", "jane@example.com", "0622222222", "jane.jpg", "FR");
when(updateRandomUserUseCase.execute(7, request)).thenReturn(updated);

ResponseEntity<UserEntity> response = userHandler.updateRandomUser(7, request);

assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(updated, response.getBody());
verify(updateRandomUserUseCase, times(1)).execute(7, request);
}

@Test
@DisplayName("Should return 404 when updateRandomUser throws UserNotFoundException")
void shouldReturnNotFoundWhenUpdateRandomUserFails() {
UserRequest request = new UserRequest("male", "Bob", "Brown", "Mr", "bob@example.com", "0633333333", "bob.jpg", "DE");
when(updateRandomUserUseCase.execute(123, request)).thenThrow(new UserNotFoundException(123));

ResponseEntity<UserEntity> response = userHandler.updateRandomUser(123, request);

assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertNull(response.getBody());
verify(updateRandomUserUseCase, times(1)).execute(123, request);
}
}
2 changes: 1 addition & 1 deletion src/test/resources/application-test.properties.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
POSTGRES_USER=your_postgres_user
POSTGRES_PASSWORD=your_postgres_password
POSTGRES_DB=your_postgres_db
POSTGRES_PORT=5433
POSTGRES_PORT=your_postgres_port