diff --git a/pom.xml b/pom.xml
index 80f07a0..7e1a68c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
2.0.4
false
**/*Application.java
- **/feature/SpringIntegrationTest.java
+ **/features/SpringIntegrationTest.java
${project.build.directory}/site/jacoco/jacoco.xml
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/config/UseCaseConfig.java b/src/main/java/com/xpeho/spring_boot_java_random_user/config/UseCaseConfig.java
new file mode 100644
index 0000000..db8d07c
--- /dev/null
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/config/UseCaseConfig.java
@@ -0,0 +1,45 @@
+package com.xpeho.spring_boot_java_random_user.config;
+
+import com.xpeho.spring_boot_java_random_user.domain.services.RemoteUserService;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
+import com.xpeho.spring_boot_java_random_user.domain.usecases.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+@Configuration
+public class UseCaseConfig {
+
+ @Bean
+ public CreateUserUseCase createUserUseCase(UserService userService) {
+ return new CreateUserUseCase(userService);
+ }
+
+ @Bean
+ public DeleteUserByIdUseCase deleteUserByIdUseCase(UserService userService) {
+ return new DeleteUserByIdUseCase(userService);
+ }
+
+ @Bean
+ public FetchAndSaveRandomUsersUseCase fetchAndSaveRandomUsersUseCase(
+ UserService userService,
+ List remoteUserServices) {
+ return new FetchAndSaveRandomUsersUseCase(userService, remoteUserServices);
+ }
+
+ @Bean
+ public FilterUsersUseCase filterUsersUseCase(UserService userService) {
+ return new FilterUsersUseCase(userService);
+ }
+
+ @Bean
+ public GetUserByIdUseCase getUserByIdUseCase(UserService userService) {
+ return new GetUserByIdUseCase(userService);
+ }
+
+ @Bean
+ public UpdateRandomUserUseCase updateRandomUserUseCase(UserService userService) {
+ return new UpdateRandomUserUseCase(userService);
+ }
+}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverter.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverter.java
index 5bff94e..5e56915 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverter.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverter.java
@@ -2,7 +2,7 @@
import com.xpeho.spring_boot_java_random_user.data.models.api.dummy.DummyUserResultDTO;
import com.xpeho.spring_boot_java_random_user.data.models.api.randomuser.RandomUserResultDTO;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import org.springframework.stereotype.Service;
@@ -10,8 +10,8 @@
@Service
public class UserConverter {
// Domain -> DAO
- public User toDao(UserEntity entity) {
- User user = new User();
+ public UserDao toDao(UserEntity entity) {
+ UserDao user = new UserDao();
user.setId(entity.id());
user.setGender(entity.gender());
user.setFirstname(entity.firstname());
@@ -25,7 +25,7 @@ public User toDao(UserEntity entity) {
}
// DAO -> Domain
- public UserEntity toDomain(User user) {
+ public UserEntity toDomain(UserDao user) {
return new UserEntity(
user.getId(),
user.getGender(),
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/User.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/UserDao.java
similarity index 97%
rename from src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/User.java
rename to src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/UserDao.java
index bdd3a8a..3421503 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/User.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/models/database/UserDao.java
@@ -9,7 +9,7 @@
@Entity
@Table(name = "users")
-public class User {
+public class UserDao {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
@@ -32,7 +32,7 @@ public class User {
private String nationality;
// Required by JPA
- public User() {
+ public UserDao() {
// No initialization needed
}
@@ -108,3 +108,4 @@ public void setNationality(String nationality) {
this.nationality = nationality;
}
}
+
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImpl.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImpl.java
index 76271af..53348d6 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImpl.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImpl.java
@@ -1,12 +1,15 @@
package com.xpeho.spring_boot_java_random_user.data.services;
import com.xpeho.spring_boot_java_random_user.data.converters.UserConverter;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.data.sources.database.UserRepository;
import com.xpeho.spring_boot_java_random_user.data.sources.database.UserSpecifications;
+import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -14,8 +17,7 @@
import java.util.stream.StreamSupport;
@Service
-
-public class UserServiceImpl implements LocalUserService {
+public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserConverter userConverter;
@@ -26,8 +28,8 @@ public UserServiceImpl(UserRepository userRepository, UserConverter userConverte
@Override
public List saveAll(List users) {
- List daoUsers = users.stream().map(userConverter::toDao).toList();
- Iterable saved = userRepository.saveAll(daoUsers);
+ List daoUsers = users.stream().map(userConverter::toDao).toList();
+ Iterable saved = userRepository.saveAll(daoUsers);
return StreamSupport.stream(saved.spliterator(), false)
.map(userConverter::toDomain)
.toList();
@@ -41,7 +43,7 @@ public Optional getById(long id) {
@Override
public UserEntity save(UserEntity user) {
- User savedUser = userRepository.save(userConverter.toDao(user));
+ UserDao savedUser = userRepository.save(userConverter.toDao(user));
return userConverter.toDomain(savedUser);
}
@@ -51,9 +53,13 @@ public void deleteById(long id) {
}
@Override
- public List filterUsers(UserFilter filter) {
- return userRepository.findAll(UserSpecifications.byFilter(filter)).stream()
+ public PaginatedUsers filterUsers(UserFilter filter, int page, int size) {
+ PageRequest pageable = PageRequest.of(page - 1, size);
+ Page result = userRepository.findAll(UserSpecifications.byFilter(filter), pageable);
+ List entities = result.getContent().stream()
.map(userConverter::toDomain)
.toList();
+ int skip = (page - 1) * size;
+ return new PaginatedUsers(entities, (int) result.getTotalElements(), skip, size);
}
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/randomuser/RandomUserApiConfig.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/UserApiConfig.java
similarity index 52%
rename from src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/randomuser/RandomUserApiConfig.java
rename to src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/UserApiConfig.java
index 882f3ff..70b6fa5 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/randomuser/RandomUserApiConfig.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/UserApiConfig.java
@@ -1,5 +1,7 @@
-package com.xpeho.spring_boot_java_random_user.data.sources.api.randomuser;
+package com.xpeho.spring_boot_java_random_user.data.sources.api;
+import com.xpeho.spring_boot_java_random_user.data.sources.api.dummy.DummyUserApi;
+import com.xpeho.spring_boot_java_random_user.data.sources.api.randomuser.RandomUserApi;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -8,7 +10,21 @@
import retrofit2.converter.gson.GsonConverterFactory;
@Configuration
-public class RandomUserApiConfig {
+public class UserApiConfig {
+
+ @Bean(name = "dummyUserRetrofit")
+ public Retrofit dummyUserRetrofit(Environment env) {
+ return new Retrofit.Builder()
+ .baseUrl(env.getRequiredProperty("dummy.api.base-url"))
+ .addConverterFactory(GsonConverterFactory.create())
+ .build();
+ }
+
+ @Bean
+ public DummyUserApi dummyUserApi(@Qualifier("dummyUserRetrofit") Retrofit dummyUserRetrofit) {
+ return dummyUserRetrofit.create(DummyUserApi.class);
+ }
+
@Bean(name = "randomUserRetrofit")
public Retrofit randomUserRetrofit(Environment env) {
return new Retrofit.Builder()
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/dummy/DummyUserApiConfig.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/dummy/DummyUserApiConfig.java
deleted file mode 100644
index 9b1dfa5..0000000
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/api/dummy/DummyUserApiConfig.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.xpeho.spring_boot_java_random_user.data.sources.api.dummy;
-
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-import retrofit2.Retrofit;
-import retrofit2.converter.gson.GsonConverterFactory;
-
-@Configuration
-public class DummyUserApiConfig {
- @Bean(name = "dummyUserRetrofit")
- public Retrofit dummyUserRetrofit(Environment env) {
- return new Retrofit.Builder()
- .baseUrl(env.getRequiredProperty("dummy.api.base-url"))
- .addConverterFactory(GsonConverterFactory.create())
- .build();
- }
-
- @Bean
- public DummyUserApi dummyUserApi(@Qualifier("dummyUserRetrofit") Retrofit dummyUserRetrofit) {
- return dummyUserRetrofit.create(DummyUserApi.class);
- }
-}
-
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserRepository.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserRepository.java
index b23c856..4d06779 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserRepository.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserRepository.java
@@ -1,8 +1,8 @@
package com.xpeho.spring_boot_java_random_user.data.sources.database;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-public interface UserRepository extends JpaRepository, JpaSpecificationExecutor {
+public interface UserRepository extends JpaRepository, JpaSpecificationExecutor {
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecifications.java b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecifications.java
index f4be154..c2aaa8b 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecifications.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecifications.java
@@ -1,6 +1,6 @@
package com.xpeho.spring_boot_java_random_user.data.sources.database;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Path;
@@ -15,7 +15,7 @@ public final class UserSpecifications {
private UserSpecifications() {
}
- public static Specification byFilter(UserFilter filter) {
+ public static Specification byFilter(UserFilter filter) {
return (user, query, criteriaBuilder) -> {
List predicates = new ArrayList<>();
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/LocalUserService.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/UserService.java
similarity index 70%
rename from src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/LocalUserService.java
rename to src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/UserService.java
index 8bb472e..19393fb 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/LocalUserService.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/services/UserService.java
@@ -1,12 +1,13 @@
package com.xpeho.spring_boot_java_random_user.domain.services;
+import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
import java.util.List;
import java.util.Optional;
-public interface LocalUserService {
+public interface UserService {
List saveAll(List users);
Optional getById(long id);
@@ -15,6 +16,7 @@ public interface LocalUserService {
void deleteById(long id);
- List filterUsers(UserFilter filter);
+ PaginatedUsers filterUsers(UserFilter filter, int page, int size);
}
+
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCase.java
index eada9af..67ee07d 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCase.java
@@ -1,31 +1,16 @@
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.entities.UserRequest;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
-@Service
public class CreateUserUseCase {
- private final LocalUserService userService;
+ private final UserService userService;
- public CreateUserUseCase(LocalUserService userService) {
+ public CreateUserUseCase(UserService userService) {
this.userService = userService;
}
- public UserEntity execute(UserRequest user) {
- UserEntity userToCreate = new UserEntity(
- null,
- user.gender(),
- user.firstname(),
- user.lastname(),
- user.civility(),
- user.email(),
- user.phone(),
- user.picture(),
- user.nat()
- );
-
- return userService.save(userToCreate);
+ public UserEntity execute(UserEntity user) {
+ return userService.save(user);
}
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCase.java
index e120db4..7071cb1 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCase.java
@@ -1,13 +1,11 @@
package com.xpeho.spring_boot_java_random_user.domain.usecases;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
-@Service
public class DeleteUserByIdUseCase {
- private final LocalUserService userService;
+ private final UserService userService;
- public DeleteUserByIdUseCase(LocalUserService userService) {
+ public DeleteUserByIdUseCase(UserService userService) {
this.userService = userService;
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCase.java
index 231dd98..bfb4c86 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCase.java
@@ -2,9 +2,8 @@
import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
import com.xpeho.spring_boot_java_random_user.domain.services.RemoteUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
import java.io.IOException;
import java.util.List;
@@ -12,14 +11,13 @@
import java.util.function.Function;
import java.util.stream.Collectors;
-@Service
public class FetchAndSaveRandomUsersUseCase {
- private final LocalUserService localUserService;
+ private final UserService userService;
private final Map remoteUserServices;
- public FetchAndSaveRandomUsersUseCase(LocalUserService localUserService, List remoteUserServices) {
- this.localUserService = localUserService;
+ public FetchAndSaveRandomUsersUseCase(UserService userService, List remoteUserServices) {
+ this.userService = userService;
this.remoteUserServices = remoteUserServices.stream()
.collect(Collectors.toMap(RemoteUserService::getSource, Function.identity()));
}
@@ -30,7 +28,7 @@ public PaginatedUsers execute(int page, int size, UserSource source) throws IOEx
throw new IllegalStateException("No remote service configured for source: " + source);
}
PaginatedUsers response = remoteUserService.fetchUsers(page, size);
- localUserService.saveAll(response.data());
+ userService.saveAll(response.data());
return response;
}
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCase.java
index a28a71d..3123293 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCase.java
@@ -1,21 +1,17 @@
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.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
-import java.util.List;
-
-@Service
public class FilterUsersUseCase {
- private final LocalUserService userService;
+ private final UserService userService;
- public FilterUsersUseCase(LocalUserService userService) {
+ public FilterUsersUseCase(UserService userService) {
this.userService = userService;
}
- public List execute(UserFilter filter) {
- return userService.filterUsers(filter);
+ public PaginatedUsers execute(UserFilter filter, int page, int size) {
+ return userService.filterUsers(filter, page, size);
}
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCase.java
index 730b3e4..09e1bc1 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCase.java
@@ -2,14 +2,12 @@
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.LocalUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
-@Service
public class GetUserByIdUseCase {
- private final LocalUserService userService;
+ private final UserService userService;
- public GetUserByIdUseCase(LocalUserService userService) {
+ public GetUserByIdUseCase(UserService userService) {
this.userService = userService;
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCase.java b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCase.java
index 5a17aad..08724c1 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCase.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCase.java
@@ -1,20 +1,17 @@
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.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
-import org.springframework.stereotype.Service;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
-@Service
public class UpdateRandomUserUseCase {
- private final LocalUserService userService;
+ private final UserService userService;
- public UpdateRandomUserUseCase(LocalUserService userService) {
+ public UpdateRandomUserUseCase(UserService userService) {
this.userService = userService;
}
- public UserEntity execute(int id, UserRequest user) {
+ public UserEntity execute(long id, UserEntity user) {
UserEntity existingUser = userService.getById(id)
.orElseThrow(() -> new UserNotFoundException(id));
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/controllers/UserController.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/controllers/UserController.java
index abe1376..9790b27 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/controllers/UserController.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/controllers/UserController.java
@@ -1,21 +1,20 @@
package com.xpeho.spring_boot_java_random_user.presentation.controllers;
-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.enums.Gender;
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserDTO;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserRequestDTO;
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
-import jakarta.validation.constraints.Max;
-import jakarta.validation.constraints.Min;
+import org.springdoc.core.annotations.ParameterObject;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
-import java.util.List;
-
@RequestMapping("/random-users")
@@ -27,8 +26,6 @@ public interface UserController {
summary = "Get random users",
description = "Fetches a paginated list of random users from the external API and saves them to the database.",
parameters = {
- @Parameter(name = "page", description = "Page number", example = "1"),
- @Parameter(name = "size", description = "Number of users per page (max 30)", example = "10"),
@Parameter(name = "source", description = "External source to use", example = "DUMMY")
}
)
@@ -36,15 +33,8 @@ public interface UserController {
@ApiResponse(responseCode = "500", description = "Internal server error")
@ApiResponse(responseCode = "503", description = "External service unavailable")
ResponseEntity getRandomUsers(
- @RequestParam(defaultValue = "1")
- @Min(1)
- int page,
- @RequestParam(defaultValue = "10")
- @Min(1)
- @Max(30)
- int size,
- @RequestParam(defaultValue = "DUMMY")
- UserSource source
+ @ParameterObject @PageableDefault(size = 10, page = 0) Pageable pageable,
+ @RequestParam(defaultValue = "DUMMY") UserSource source
);
@GetMapping("/{id}")
@@ -58,47 +48,37 @@ ResponseEntity getRandomUsers(
@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 getUserById(
- @PathVariable
- int id
- );
+ ResponseEntity getUserById(@PathVariable int id);
@PutMapping("/{id}")
@Operation(
summary = "Modify a random user",
description = "Giving a random user id, modify the content of the user",
parameters = {
- @Parameter(name = "id", description = "id of the requested user"),
- @Parameter(name = "UserEntity", description = "changeable parameters")
+ @Parameter(name = "id", description = "id of the requested user")
}
)
@ApiResponse(responseCode = "200", description = "User successfully modified and saved")
@ApiResponse(responseCode = "404", description = "The requested user does not exist")
@ApiResponse(responseCode = "500", description = "Internal server error")
- ResponseEntity updateRandomUser(
- @PathVariable
- int id,
- @RequestBody
- UserRequest user
- );
+ ResponseEntity updateRandomUser(@PathVariable int id, @RequestBody UserRequestDTO user);
@PostMapping("")
@Operation(
summary = "Create a user",
description = "Creates a new user in the database.",
parameters = {
- @Parameter(name = "UserRequest", description = "User data to persist")
+ @Parameter(name = "UserRequestDTO", description = "User data to persist")
}
)
@ApiResponse(responseCode = "201", description = "User successfully created")
@ApiResponse(responseCode = "500", description = "Internal server error")
- ResponseEntity createUser(@RequestBody UserRequest user);
-
+ ResponseEntity createUser(@RequestBody UserRequestDTO user);
@GetMapping("/filter")
@Operation(
summary = "Filter users",
- description = "Search users by optional filters on gender, firstname, lastname, civility, email, phone and nationality. All filters are case-insensitive and support partial matching.",
+ description = "Search users by optional filters. Supports pagination via page/size query params.",
parameters = {
@Parameter(name = "gender", description = "Filter by gender (MALE or FEMALE)"),
@Parameter(name = "firstname", description = "Filter by firstname"),
@@ -109,16 +89,17 @@ ResponseEntity updateRandomUser(
@Parameter(name = "nat", description = "Filter by nationality")
}
)
- @ApiResponse(responseCode = "200", description = "Filtered list of users")
+ @ApiResponse(responseCode = "200", description = "Paginated filtered list of users")
@ApiResponse(responseCode = "500", description = "Internal server error")
- ResponseEntity> filterUsers(
+ ResponseEntity filterUsers(
@RequestParam(required = false) Gender gender,
@RequestParam(required = false) String firstname,
@RequestParam(required = false) String lastname,
@RequestParam(required = false) String civility,
@RequestParam(required = false) String email,
@RequestParam(required = false) String phone,
- @RequestParam(required = false) String nat
+ @RequestParam(required = false) String nat,
+ @ParameterObject @PageableDefault(size = 10, page = 0) Pageable pageable
);
@DeleteMapping("/{id}")
@@ -132,8 +113,5 @@ ResponseEntity> filterUsers(
@ApiResponse(responseCode = "204", description = "User successfully deleted")
@ApiResponse(responseCode = "404", description = "The requested user does not exist")
@ApiResponse(responseCode = "500", description = "Internal server error")
- void deleteUserById(
- @PathVariable
- int id
- );
+ void deleteUserById(@PathVariable int id);
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserDTO.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserDTO.java
new file mode 100644
index 0000000..d05715c
--- /dev/null
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserDTO.java
@@ -0,0 +1,15 @@
+package com.xpeho.spring_boot_java_random_user.presentation.dto;
+
+public record UserDTO(
+ Long id,
+ String gender,
+ String firstname,
+ String lastname,
+ String civility,
+ String email,
+ String phone,
+ String picture,
+ String nat
+) {
+}
+
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/entities/UserRequest.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserRequestDTO.java
similarity index 66%
rename from src/main/java/com/xpeho/spring_boot_java_random_user/domain/entities/UserRequest.java
rename to src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserRequestDTO.java
index a923b54..b82fbc2 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/domain/entities/UserRequest.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserRequestDTO.java
@@ -1,6 +1,6 @@
-package com.xpeho.spring_boot_java_random_user.domain.entities;
+package com.xpeho.spring_boot_java_random_user.presentation.dto;
-public record UserRequest(
+public record UserRequestDTO(
String gender,
String firstname,
String lastname,
@@ -11,3 +11,4 @@ public record UserRequest(
String nat
) {
}
+
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserResponseDTO.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserResponseDTO.java
index 06e7084..f61e49c 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserResponseDTO.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/dto/UserResponseDTO.java
@@ -1,8 +1,6 @@
package com.xpeho.spring_boot_java_random_user.presentation.dto;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
-
import java.util.List;
-public record UserResponseDTO(List data, int total, int skip, int limit) {
+public record UserResponseDTO(List data, int total, int skip, int limit) {
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/handlers/UserHandler.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/handlers/UserHandler.java
index c6d81c2..c1551c4 100644
--- a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/handlers/UserHandler.java
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/handlers/UserHandler.java
@@ -3,15 +3,18 @@
import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.usecases.*;
import com.xpeho.spring_boot_java_random_user.presentation.controllers.UserController;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserDTO;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserRequestDTO;
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
+import com.xpeho.spring_boot_java_random_user.presentation.mappers.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
@@ -19,7 +22,6 @@
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
-import java.util.List;
@Validated
@@ -52,13 +54,14 @@ public UserHandler(
this.filterUsersUseCase = filterUsersUseCase;
}
-
@Override
- public ResponseEntity getRandomUsers(int page, int size, UserSource source) {
+ public ResponseEntity getRandomUsers(Pageable pageable, UserSource source) {
try {
+ int page = pageable.getPageNumber() + 1; // 0-based → 1-based
+ int size = pageable.getPageSize();
PaginatedUsers result = fetchAndSaveRandomUsersUseCase.execute(page, size, source);
UserResponseDTO response = new UserResponseDTO(
- result.data(),
+ result.data().stream().map(UserMapper::toDTO).toList(),
result.total(),
result.skip(),
result.limit()
@@ -71,10 +74,11 @@ public ResponseEntity getRandomUsers(int page, int size, UserSo
}
@Override
- public ResponseEntity updateRandomUser(int id, UserRequest user) {
+ public ResponseEntity updateRandomUser(int id, UserRequestDTO user) {
try {
- UserEntity savedUser = updateRandomUserUseCase.execute(id, user);
- return ResponseEntity.ok(savedUser);
+ UserEntity input = toUserEntity(user);
+ UserEntity savedUser = updateRandomUserUseCase.execute(id, input);
+ return ResponseEntity.ok(UserMapper.toDTO(savedUser));
} catch (UserNotFoundException e) {
logUserNotFound(e);
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
@@ -82,31 +86,40 @@ public ResponseEntity updateRandomUser(int id, UserRequest user) {
}
@Override
- public ResponseEntity getUserById(int id) {
+ public ResponseEntity getUserById(int id) {
try {
UserEntity user = getUserByIdUseCase.execute(id);
- return ResponseEntity.ok(user);
+ return ResponseEntity.ok(UserMapper.toDTO(user));
} catch (UserNotFoundException e) {
logUserNotFound(e);
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
-
@Override
- public ResponseEntity createUser(@RequestBody UserRequest user) {
- UserEntity createdUser = createUserUseCase.execute(user);
- return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
+ public ResponseEntity createUser(@RequestBody UserRequestDTO user) {
+ UserEntity input = toUserEntity(user);
+ UserEntity createdUser = createUserUseCase.execute(input);
+ return ResponseEntity.status(HttpStatus.CREATED).body(UserMapper.toDTO(createdUser));
}
@Override
- public ResponseEntity> filterUsers(
+ public ResponseEntity filterUsers(
Gender gender, String firstname, String lastname,
- String civility, String email, String phone, String nat
+ String civility, String email, String phone, String nat,
+ Pageable pageable
) {
UserFilter filter = new UserFilter(gender, firstname, lastname, civility, email, phone, nat);
- List users = filterUsersUseCase.execute(filter);
- return ResponseEntity.ok(users);
+ int page = pageable.getPageNumber() + 1;
+ int size = pageable.getPageSize();
+ PaginatedUsers result = filterUsersUseCase.execute(filter, page, size);
+ UserResponseDTO response = new UserResponseDTO(
+ result.data().stream().map(UserMapper::toDTO).toList(),
+ result.total(),
+ result.skip(),
+ result.limit()
+ );
+ return ResponseEntity.ok(response);
}
@Override
@@ -118,6 +131,11 @@ public void deleteUserById(int id) {
}
}
+ private UserEntity toUserEntity(UserRequestDTO dto) {
+ return new UserEntity(null, dto.gender(), dto.firstname(), dto.lastname(),
+ dto.civility(), dto.email(), dto.phone(), dto.picture(), dto.nat());
+ }
+
private void logUserNotFound(UserNotFoundException e) {
logger.warn(USER_NOT_FOUND_LOG, e.getMessage());
}
diff --git a/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/mappers/UserMapper.java b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/mappers/UserMapper.java
new file mode 100644
index 0000000..251c1ad
--- /dev/null
+++ b/src/main/java/com/xpeho/spring_boot_java_random_user/presentation/mappers/UserMapper.java
@@ -0,0 +1,25 @@
+package com.xpeho.spring_boot_java_random_user.presentation.mappers;
+
+import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserDTO;
+
+public class UserMapper {
+
+ private UserMapper() {
+ }
+
+ public static UserDTO toDTO(UserEntity entity) {
+ return new UserDTO(
+ entity.id(),
+ entity.gender(),
+ entity.firstname(),
+ entity.lastname(),
+ entity.civility(),
+ entity.email(),
+ entity.phone(),
+ entity.picture(),
+ entity.nat()
+ );
+ }
+}
+
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverterTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverterTest.java
index 8e97b5c..a66baec 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverterTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/data/converters/UserConverterTest.java
@@ -5,7 +5,7 @@
import com.xpeho.spring_boot_java_random_user.data.models.api.randomuser.RandomUserPictureDTO;
import com.xpeho.spring_boot_java_random_user.data.models.api.randomuser.RandomUserResultDTO;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -104,7 +104,7 @@ void shouldHandleMissingNestedFieldsFromRandomUserApiModel() {
@DisplayName("Should convert domain to DB and back without losing data")
void shouldConvertDomainToDbAndBackWithoutLosingData() {
UserEntity entity = new UserEntity(1L, "male", "John", "Doe", "Mr", "john@doe.com", "1234", "pic.jpg", "FR");
- User dao = converter.toDao(entity);
+ UserDao dao = converter.toDao(entity);
assertEquals(entity.id(), dao.getId());
assertEquals(entity.firstname(), dao.getFirstname());
assertEquals(entity.lastname(), dao.getLastname());
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImplTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImplTest.java
index 942d99e..f0b6b7a 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImplTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/data/services/UserServiceImplTest.java
@@ -1,14 +1,18 @@
package com.xpeho.spring_boot_java_random_user.data.services;
import com.xpeho.spring_boot_java_random_user.data.converters.UserConverter;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.data.sources.database.UserRepository;
+import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import java.util.Collections;
@@ -17,6 +21,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -36,12 +41,10 @@ void setUp() {
@Test
@DisplayName("Should return mapped user when id exists")
void shouldReturnMappedUserWhenIdExists() {
- User dao = new User();
+ UserDao dao = new UserDao();
dao.setId(1L);
dao.setFirstname("John");
-
UserEntity expected = new UserEntity(1L, "male", "John", "Doe", "Mr", "john@doe.com", "1234", "pic.jpg", "FR");
-
when(userRepository.findById(1L)).thenReturn(Optional.of(dao));
when(userConverter.toDomain(dao)).thenReturn(expected);
@@ -68,14 +71,11 @@ void shouldReturnEmptyOptionalWhenIdDoesNotExist() {
@DisplayName("Should save mapped user and return mapped domain entity")
void shouldSaveMappedUserAndReturnMappedDomainEntity() {
UserEntity input = new UserEntity(3L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US");
-
- User daoToSave = new User();
+ UserDao daoToSave = new UserDao();
daoToSave.setFirstname("Alice");
-
- User savedDao = new User();
+ UserDao savedDao = new UserDao();
savedDao.setId(3L);
savedDao.setFirstname("Alice");
-
UserEntity expected = new UserEntity(3L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US");
when(userConverter.toDao(input)).thenReturn(daoToSave);
@@ -91,61 +91,58 @@ void shouldSaveMappedUserAndReturnMappedDomainEntity() {
}
@Test
- @DisplayName("Should build a specification and call repository for filtered users")
+ @DisplayName("Should return paginated users when filtering with gender")
void shouldFilterUsersWithGender() {
UserFilter filter = new UserFilter(Gender.MALE, "John", null, null, null, null, null);
-
- User dao = new User();
+ UserDao dao = new UserDao();
dao.setId(1L);
dao.setFirstname("John");
-
UserEntity expected = new UserEntity(1L, "male", "John", "Doe", "Mr", "john@doe.com", "1234", "pic.jpg", "FR");
+ Page page = new PageImpl<>(List.of(dao));
- when(userRepository.findAll(org.mockito.ArgumentMatchers.>any()))
- .thenReturn(List.of(dao));
+ when(userRepository.findAll(any(Specification.class), any(Pageable.class))).thenReturn(page);
when(userConverter.toDomain(dao)).thenReturn(expected);
- List result = userService.filterUsers(filter);
+ PaginatedUsers result = userService.filterUsers(filter, 1, 10);
- assertEquals(1, result.size());
- assertEquals(expected, result.get(0));
- verify(userRepository).findAll(org.mockito.ArgumentMatchers.>any());
+ assertEquals(1, result.data().size());
+ assertEquals(expected, result.data().get(0));
+ assertEquals(1, result.total());
+ verify(userRepository).findAll(any(Specification.class), any(Pageable.class));
verify(userConverter).toDomain(dao);
}
@Test
- @DisplayName("Should call repository when gender filter is null")
+ @DisplayName("Should return paginated users when filtering with null gender")
void shouldFilterUsersWithNullGender() {
UserFilter filter = new UserFilter(null, null, "Smith", null, null, null, null);
-
- User dao = new User();
+ UserDao dao = new UserDao();
dao.setId(2L);
dao.setLastname("Smith");
-
UserEntity expected = new UserEntity(2L, "female", "Alice", "Smith", "Ms", "alice@smith.com", "5678", "pic2.jpg", "US");
+ Page page = new PageImpl<>(List.of(dao));
- when(userRepository.findAll(org.mockito.ArgumentMatchers.>any()))
- .thenReturn(List.of(dao));
+ when(userRepository.findAll(any(Specification.class), any(Pageable.class))).thenReturn(page);
when(userConverter.toDomain(dao)).thenReturn(expected);
- List result = userService.filterUsers(filter);
+ PaginatedUsers result = userService.filterUsers(filter, 1, 10);
- assertEquals(1, result.size());
- assertEquals(expected, result.get(0));
- verify(userRepository).findAll(org.mockito.ArgumentMatchers.>any());
+ assertEquals(1, result.data().size());
+ verify(userRepository).findAll(any(Specification.class), any(Pageable.class));
}
@Test
- @DisplayName("Should return empty list when no users match filter")
+ @DisplayName("Should return empty paginated result when no users match filter")
void shouldReturnEmptyListWhenNoUsersMatchFilter() {
UserFilter filter = new UserFilter(Gender.FEMALE, "Unknown", null, null, null, null, null);
+ Page emptyPage = new PageImpl<>(Collections.emptyList());
- when(userRepository.findAll(org.mockito.ArgumentMatchers.>any()))
- .thenReturn(Collections.emptyList());
+ when(userRepository.findAll(any(Specification.class), any(Pageable.class))).thenReturn(emptyPage);
- List result = userService.filterUsers(filter);
+ PaginatedUsers result = userService.filterUsers(filter, 1, 10);
- assertTrue(result.isEmpty());
- verify(userRepository).findAll(org.mockito.ArgumentMatchers.>any());
+ assertTrue(result.data().isEmpty());
+ assertEquals(0, result.total());
+ verify(userRepository).findAll(any(Specification.class), any(Pageable.class));
}
}
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecificationsTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecificationsTest.java
index cbe3095..f96c5a2 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecificationsTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/data/sources/database/UserSpecificationsTest.java
@@ -1,6 +1,6 @@
package com.xpeho.spring_boot_java_random_user.data.sources.database;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
import jakarta.persistence.criteria.*;
import org.junit.jupiter.api.BeforeEach;
@@ -11,11 +11,10 @@
import static org.mockito.Mockito.*;
class UserSpecificationsTest {
- private Root user;
+ private Root user;
private CriteriaQuery> query;
private CriteriaBuilder cb;
private Expression lowerExpr;
- private Predicate predicate;
@BeforeEach
@SuppressWarnings("unchecked")
@@ -24,7 +23,7 @@ void setUp() {
query = mock(CriteriaQuery.class);
cb = mock(CriteriaBuilder.class);
lowerExpr = mock(Expression.class);
- predicate = mock(Predicate.class);
+ Predicate predicate = mock(Predicate.class);
when(cb.lower(any())).thenReturn(lowerExpr);
when(cb.equal(any(), anyString())).thenReturn(predicate);
when(cb.like(any(Expression.class), anyString())).thenReturn(predicate);
@@ -38,7 +37,7 @@ void setUp() {
void shouldAddLikePredicatesForAllTextFields() {
UserFilter filter = new UserFilter(null, "John", "Doe", "Mr", "john@doe.com", "1234", "FR");
- Specification spec = UserSpecifications.byFilter(filter);
+ Specification spec = UserSpecifications.byFilter(filter);
spec.toPredicate(user, query, cb);
verify(user).get("firstname");
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCaseTest.java
index 4a99dd5..4f9d894 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/CreateUserUseCaseTest.java
@@ -1,8 +1,7 @@
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.entities.UserRequest;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+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;
@@ -13,33 +12,30 @@
import static org.mockito.Mockito.when;
class CreateUserUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private CreateUserUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
useCase = new CreateUserUseCase(userService);
}
@Test
- @DisplayName("Should create a user without keeping the input id")
+ @DisplayName("Should create a user by passing the UserEntity directly")
void shouldCreateUserWithoutKeepingInputId() {
- UserRequest payload = new UserRequest(
- "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
+ UserEntity input = new UserEntity(
+ null, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
);
UserEntity createdUser = new UserEntity(
1L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
);
- UserEntity expectedSavedUser = new UserEntity(
- null, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
- );
- when(userService.save(expectedSavedUser)).thenReturn(createdUser);
+ when(userService.save(input)).thenReturn(createdUser);
- UserEntity result = useCase.execute(payload);
+ UserEntity result = useCase.execute(input);
assertEquals(createdUser, result);
- verify(userService).save(expectedSavedUser);
+ verify(userService).save(input);
}
}
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCaseTest.java
index 73d8000..923804e 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/DeleteUserByIdUseCaseTest.java
@@ -1,6 +1,6 @@
package com.xpeho.spring_boot_java_random_user.domain.usecases;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+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;
@@ -8,12 +8,12 @@
import static org.mockito.Mockito.*;
class DeleteUserByIdUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private DeleteUserByIdUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
useCase = new DeleteUserByIdUseCase(userService);
}
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCaseTest.java
index 1b867da..4cf3efc 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FetchAndSaveRandomUsersUseCaseTest.java
@@ -3,7 +3,7 @@
import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+import com.xpeho.spring_boot_java_random_user.domain.services.UserService;
import com.xpeho.spring_boot_java_random_user.domain.services.RemoteUserService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@@ -16,14 +16,14 @@
import static org.mockito.Mockito.*;
class FetchAndSaveRandomUsersUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private RemoteUserService dummyRemoteUserService;
private RemoteUserService randomRemoteUserService;
private FetchAndSaveRandomUsersUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
dummyRemoteUserService = mock(RemoteUserService.class);
randomRemoteUserService = mock(RemoteUserService.class);
when(dummyRemoteUserService.getSource()).thenReturn(UserSource.DUMMY);
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCaseTest.java
index 368f69f..aae4138 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/FilterUsersUseCaseTest.java
@@ -1,9 +1,10 @@
package com.xpeho.spring_boot_java_random_user.domain.usecases;
+import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+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;
@@ -15,55 +16,58 @@
import static org.mockito.Mockito.*;
class FilterUsersUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private FilterUsersUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
useCase = new FilterUsersUseCase(userService);
}
@Test
- @DisplayName("Should return filtered users matching the filter")
+ @DisplayName("Should return paginated filtered users matching the filter")
void shouldReturnFilteredUsers() {
UserFilter filter = new UserFilter(Gender.MALE, "John", null, null, null, null, null);
- List expected = List.of(
+ List users = List.of(
new UserEntity(1L, "male", "John", "Doe", "Mr", "john@example.com", "0600000000", "http://pic.jpg", "FR")
);
- when(userService.filterUsers(filter)).thenReturn(expected);
+ PaginatedUsers expected = new PaginatedUsers(users, 1, 0, 10);
+ when(userService.filterUsers(filter, 1, 10)).thenReturn(expected);
- List result = useCase.execute(filter);
+ PaginatedUsers result = useCase.execute(filter, 1, 10);
assertEquals(expected, result);
- verify(userService).filterUsers(filter);
+ verify(userService).filterUsers(filter, 1, 10);
}
@Test
- @DisplayName("Should return empty list when no users match the filter")
+ @DisplayName("Should return empty paginated result when no users match the filter")
void shouldReturnEmptyListWhenNoMatch() {
UserFilter filter = new UserFilter(Gender.FEMALE, "Unknown", null, null, null, null, null);
- when(userService.filterUsers(filter)).thenReturn(Collections.emptyList());
+ PaginatedUsers empty = new PaginatedUsers(Collections.emptyList(), 0, 0, 10);
+ when(userService.filterUsers(filter, 1, 10)).thenReturn(empty);
- List result = useCase.execute(filter);
+ PaginatedUsers result = useCase.execute(filter, 1, 10);
- assertTrue(result.isEmpty());
- verify(userService).filterUsers(filter);
+ assertTrue(result.data().isEmpty());
+ verify(userService).filterUsers(filter, 1, 10);
}
@Test
@DisplayName("Should pass filter with all fields to the service")
void shouldPassFilterWithAllFields() {
UserFilter filter = new UserFilter(Gender.FEMALE, "Alice", "Smith", "Ms", "alice@example.com", "0611111111", "US");
- List expected = List.of(
+ List users = List.of(
new UserEntity(5L, "female", "Alice", "Smith", "Ms", "alice@example.com", "0611111111", "http://pic2.jpg", "US")
);
- when(userService.filterUsers(filter)).thenReturn(expected);
+ PaginatedUsers expected = new PaginatedUsers(users, 1, 0, 10);
+ when(userService.filterUsers(filter, 1, 10)).thenReturn(expected);
- List result = useCase.execute(filter);
+ PaginatedUsers result = useCase.execute(filter, 1, 10);
assertEquals(expected, result);
- verify(userService, times(1)).filterUsers(filter);
+ verify(userService, times(1)).filterUsers(filter, 1, 10);
verifyNoMoreInteractions(userService);
}
}
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCaseTest.java
index cbbf0c1..f22956c 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/GetUserByIdUseCaseTest.java
@@ -2,7 +2,7 @@
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.LocalUserService;
+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;
@@ -13,12 +13,12 @@
import static org.mockito.Mockito.*;
class GetUserByIdUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private GetUserByIdUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
useCase = new GetUserByIdUseCase(userService);
}
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCaseTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCaseTest.java
index 1d8a5a8..c92772a 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCaseTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/domain/usecases/UpdateRandomUserUseCaseTest.java
@@ -1,9 +1,8 @@
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.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
-import com.xpeho.spring_boot_java_random_user.domain.services.LocalUserService;
+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;
@@ -19,12 +18,12 @@
import static org.mockito.Mockito.when;
class UpdateRandomUserUseCaseTest {
- private LocalUserService userService;
+ private UserService userService;
private UpdateRandomUserUseCase useCase;
@BeforeEach
void setUp() {
- userService = mock(LocalUserService.class);
+ userService = mock(UserService.class);
useCase = new UpdateRandomUserUseCase(userService);
}
@@ -34,39 +33,35 @@ void shouldUpdateExistingUserAndPreserveItsId() {
UserEntity existingUser = new UserEntity(
42L, "male", "John", "Doe", "Mr", "john@doe.com", "1234", "pic.jpg", "FR"
);
- UserRequest request = new UserRequest(
- "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
+ UserEntity input = new UserEntity(
+ null, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
);
UserEntity savedUser = new UserEntity(
42L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
);
when(userService.getById(42)).thenReturn(Optional.of(existingUser));
- when(userService.save(new UserEntity(
- 42L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
- ))).thenReturn(savedUser);
+ when(userService.save(savedUser)).thenReturn(savedUser);
- UserEntity result = useCase.execute(42, request);
+ UserEntity result = useCase.execute(42, input);
assertEquals(savedUser, result);
verify(userService).getById(42);
- verify(userService).save(new UserEntity(
- 42L, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
- ));
+ verify(userService).save(savedUser);
}
@Test
@DisplayName("Should throw when updating a user that does not exist")
void shouldThrowWhenUserDoesNotExist() {
- UserRequest request = new UserRequest(
- "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
+ UserEntity input = new UserEntity(
+ null, "female", "Alice", "Smith", "Mrs", "alice@smith.com", "5678", "new-pic.jpg", "US"
);
when(userService.getById(99)).thenReturn(Optional.empty());
UserNotFoundException exception = assertThrows(
UserNotFoundException.class,
- () -> useCase.execute(99, request)
+ () -> useCase.execute(99, input)
);
assertEquals("User not found with id: 99", exception.getMessage());
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserGetByIdContainerTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserGetByIdContainerTest.java
index 1468bd9..87cb552 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserGetByIdContainerTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserGetByIdContainerTest.java
@@ -1,8 +1,8 @@
package com.xpeho.spring_boot_java_random_user.presentation;
-import com.xpeho.spring_boot_java_random_user.data.models.database.User;
+import com.xpeho.spring_boot_java_random_user.data.models.database.UserDao;
import com.xpeho.spring_boot_java_random_user.data.sources.database.UserRepository;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserDTO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@@ -60,7 +60,7 @@ void setUp() {
@Test
@DisplayName("GET /random-users/{id} should return 200 with persisted user")
void shouldReturnUserByIdWhenUserExists() {
- User user = new User();
+ UserDao user = new UserDao();
user.setGender("female");
user.setFirstname("Jane");
user.setLastname("Doe");
@@ -70,11 +70,11 @@ void shouldReturnUserByIdWhenUserExists() {
user.setPicture("https://example.com/jane.jpg");
user.setNationality("FR");
- User saved = userRepository.saveAndFlush(user);
+ UserDao saved = userRepository.saveAndFlush(user);
- ResponseEntity response = restTemplate.withBasicAuth(TEST_USERNAME, TEST_PASSWORD).getForEntity(
+ ResponseEntity response = restTemplate.withBasicAuth(TEST_USERNAME, TEST_PASSWORD).getForEntity(
"/random-users/{id}",
- UserEntity.class,
+ UserDTO.class,
saved.getId()
);
@@ -88,9 +88,9 @@ void shouldReturnUserByIdWhenUserExists() {
@Test
@DisplayName("GET /random-users/{id} should return 404 when user does not exist")
void shouldReturnNotFoundWhenUserDoesNotExist() {
- ResponseEntity response = restTemplate.withBasicAuth(TEST_USERNAME, TEST_PASSWORD).getForEntity(
+ ResponseEntity response = restTemplate.withBasicAuth(TEST_USERNAME, TEST_PASSWORD).getForEntity(
"/random-users/{id}",
- UserEntity.class,
+ UserDTO.class,
-1
);
diff --git a/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserHandlerTest.java b/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserHandlerTest.java
index 3ff8b59..b6d51bf 100644
--- a/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserHandlerTest.java
+++ b/src/test/java/com/xpeho/spring_boot_java_random_user/presentation/UserHandlerTest.java
@@ -3,16 +3,20 @@
import com.xpeho.spring_boot_java_random_user.domain.entities.PaginatedUsers;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserEntity;
import com.xpeho.spring_boot_java_random_user.domain.entities.UserFilter;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
import com.xpeho.spring_boot_java_random_user.domain.enums.Gender;
import com.xpeho.spring_boot_java_random_user.domain.enums.UserSource;
import com.xpeho.spring_boot_java_random_user.domain.exceptions.UserNotFoundException;
import com.xpeho.spring_boot_java_random_user.domain.usecases.*;
-import com.xpeho.spring_boot_java_random_user.presentation.handlers.UserHandler;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserDTO;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserRequestDTO;
import com.xpeho.spring_boot_java_random_user.presentation.dto.UserResponseDTO;
+import com.xpeho.spring_boot_java_random_user.presentation.handlers.UserHandler;
+import com.xpeho.spring_boot_java_random_user.presentation.mappers.UserMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -46,37 +50,34 @@ void setUp() {
@Test
@DisplayName("Should return 200 and paged users when getRandomUsers succeeds")
void shouldReturnOkWhenGetRandomUsersSucceeds() throws IOException {
- int page = 1;
- int size = 10;
+ Pageable pageable = PageRequest.of(0, 10);
List users = List.of(
new UserEntity(1L, "male", "John", "Doe", "Mr", "john@example.com", "0600000000", "pic.jpg", "FR")
);
PaginatedUsers paginatedUsers = new PaginatedUsers(users, 50, 0, 10);
- when(fetchAndSaveRandomUsersUseCase.execute(page, size, UserSource.DUMMY)).thenReturn(paginatedUsers);
+ when(fetchAndSaveRandomUsersUseCase.execute(1, 10, UserSource.DUMMY)).thenReturn(paginatedUsers);
- ResponseEntity response = userHandler.getRandomUsers(page, size, UserSource.DUMMY);
+ ResponseEntity response = userHandler.getRandomUsers(pageable, UserSource.DUMMY);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
- assertEquals(users, response.getBody().data());
+ assertEquals(users.stream().map(UserMapper::toDTO).toList(), response.getBody().data());
assertEquals(50, response.getBody().total());
assertEquals(0, response.getBody().skip());
assertEquals(10, response.getBody().limit());
- verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(page, size, UserSource.DUMMY);
+ verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(1, 10, UserSource.DUMMY);
}
@Test
@DisplayName("Should return 500 when getRandomUsers throws IOException")
void shouldReturnInternalServerErrorWhenGetRandomUsersFails() throws IOException {
- int page = 1;
- int size = 10;
- when(fetchAndSaveRandomUsersUseCase.execute(page, size, UserSource.RANDOM_USER)).thenThrow(new IOException("downstream unavailable"));
+ Pageable pageable = PageRequest.of(0, 10);
+ when(fetchAndSaveRandomUsersUseCase.execute(1, 10, UserSource.RANDOM_USER)).thenThrow(new IOException("downstream unavailable"));
- ResponseEntity response = userHandler.getRandomUsers(page, size, UserSource.RANDOM_USER);
+ ResponseEntity response = userHandler.getRandomUsers(pageable, UserSource.RANDOM_USER);
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
assertNull(response.getBody());
- verify(fetchAndSaveRandomUsersUseCase, times(1)).execute(page, size, UserSource.RANDOM_USER);
}
@Test
@@ -85,10 +86,10 @@ 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 response = userHandler.getUserById(42);
+ ResponseEntity response = userHandler.getUserById(42);
assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(user, response.getBody());
+ assertEquals(UserMapper.toDTO(user), response.getBody());
verify(getUserByIdUseCase, times(1)).execute(42);
}
@@ -97,62 +98,60 @@ void shouldReturnOkWhenGetUserByIdSucceeds() {
void shouldReturnNotFoundWhenGetUserByIdFails() {
when(getUserByIdUseCase.execute(99)).thenThrow(new UserNotFoundException(99));
- ResponseEntity response = userHandler.getUserById(99);
+ ResponseEntity 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");
+ UserRequestDTO request = new UserRequestDTO("female", "Jane", "Doe", "Ms", "jane@example.com", "0622222222", "jane.jpg", "FR");
+ UserEntity input = new UserEntity(null, "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);
+ when(updateRandomUserUseCase.execute(7, input)).thenReturn(updated);
- ResponseEntity response = userHandler.updateRandomUser(7, request);
+ ResponseEntity response = userHandler.updateRandomUser(7, request);
assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(updated, response.getBody());
- verify(updateRandomUserUseCase, times(1)).execute(7, request);
+ assertEquals(UserMapper.toDTO(updated), response.getBody());
+ verify(updateRandomUserUseCase, times(1)).execute(7, input);
}
@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));
+ UserRequestDTO request = new UserRequestDTO("male", "Bob", "Brown", "Mr", "bob@example.com", "0633333333", "bob.jpg", "DE");
+ UserEntity input = new UserEntity(null, "male", "Bob", "Brown", "Mr", "bob@example.com", "0633333333", "bob.jpg", "DE");
+ when(updateRandomUserUseCase.execute(123, input)).thenThrow(new UserNotFoundException(123));
- ResponseEntity response = userHandler.updateRandomUser(123, request);
+ ResponseEntity response = userHandler.updateRandomUser(123, request);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertNull(response.getBody());
- verify(updateRandomUserUseCase, times(1)).execute(123, request);
}
@Test
@DisplayName("Should return 201 and created user when createUser succeeds")
void shouldReturnCreatedWhenCreateUserSucceeds() {
- UserRequest request = new UserRequest("female", "Emma", "Stone", "Ms", "emma@example.com", "0644444444", "emma.jpg", "FR");
+ UserRequestDTO request = new UserRequestDTO("female", "Emma", "Stone", "Ms", "emma@example.com", "0644444444", "emma.jpg", "FR");
+ UserEntity input = new UserEntity(null, "female", "Emma", "Stone", "Ms", "emma@example.com", "0644444444", "emma.jpg", "FR");
UserEntity created = new UserEntity(10L, "female", "Emma", "Stone", "Ms", "emma@example.com", "0644444444", "emma.jpg", "FR");
- when(createUserUseCase.execute(request)).thenReturn(created);
+ when(createUserUseCase.execute(input)).thenReturn(created);
- ResponseEntity response = userHandler.createUser(request);
+ ResponseEntity response = userHandler.createUser(request);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
- assertEquals(created, response.getBody());
- verify(createUserUseCase, times(1)).execute(request);
+ assertEquals(UserMapper.toDTO(created), response.getBody());
+ verify(createUserUseCase, times(1)).execute(input);
}
@Test
@DisplayName("Should return 204 when deleteUserById succeeds")
void shouldReturnNoContentWhenDeleteUserByIdSucceeds() {
- int userId = 42;
-
- userHandler.deleteUserById(userId);
-
- verify(deleteUserUseCase, times(1)).execute(userId);
+ userHandler.deleteUserById(42);
+ verify(deleteUserUseCase, times(1)).execute(42);
}
@Test
@@ -160,41 +159,42 @@ void shouldReturnNoContentWhenDeleteUserByIdSucceeds() {
void shouldLogWarningWhenDeleteUserByIdFails() {
int userId = 123;
doThrow(new UserNotFoundException(userId)).when(deleteUserUseCase).execute(userId);
-
userHandler.deleteUserById(userId);
-
verify(deleteUserUseCase, times(1)).execute(userId);
}
@Test
@DisplayName("Should return 200 and filtered users when filterUsers succeeds")
void shouldReturnOkWhenFilterUsersSucceeds() {
+ Pageable pageable = PageRequest.of(0, 10);
UserFilter filter = new UserFilter(Gender.MALE, null, null, null, null, null, "FR");
List users = List.of(
new UserEntity(1L, "male", "John", "Doe", "Mr", "john@example.com", "0600000000", "pic.jpg", "FR")
);
- when(filterUsersUseCase.execute(filter)).thenReturn(users);
+ PaginatedUsers paginatedUsers = new PaginatedUsers(users, 1, 0, 10);
+ when(filterUsersUseCase.execute(filter, 1, 10)).thenReturn(paginatedUsers);
- ResponseEntity> response = userHandler.filterUsers(Gender.MALE, null, null, null, null, null, "FR");
+ ResponseEntity response = userHandler.filterUsers(Gender.MALE, null, null, null, null, null, "FR", pageable);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
- assertEquals(1, response.getBody().size());
- assertEquals(users, response.getBody());
- verify(filterUsersUseCase, times(1)).execute(filter);
+ assertEquals(1, response.getBody().data().size());
+ assertEquals(users.stream().map(UserMapper::toDTO).toList(), response.getBody().data());
+ verify(filterUsersUseCase, times(1)).execute(filter, 1, 10);
}
@Test
@DisplayName("Should return 200 and empty list when no users match filter")
void shouldReturnOkWithEmptyListWhenNoUsersMatchFilter() {
+ Pageable pageable = PageRequest.of(0, 10);
UserFilter filter = new UserFilter(null, "NonExistent", null, null, null, null, null);
- when(filterUsersUseCase.execute(filter)).thenReturn(List.of());
+ PaginatedUsers emptyResult = new PaginatedUsers(List.of(), 0, 0, 10);
+ when(filterUsersUseCase.execute(filter, 1, 10)).thenReturn(emptyResult);
- ResponseEntity> response = userHandler.filterUsers(null, "NonExistent", null, null, null, null, null);
+ ResponseEntity response = userHandler.filterUsers(null, "NonExistent", null, null, null, null, null, pageable);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertNotNull(response.getBody());
- assertTrue(response.getBody().isEmpty());
- verify(filterUsersUseCase, times(1)).execute(filter);
+ assertTrue(response.getBody().data().isEmpty());
}
}
diff --git a/src/test/java/feature/CucumberIntegrationTest.java b/src/test/java/features/CucumberIntegrationTest.java
similarity index 96%
rename from src/test/java/feature/CucumberIntegrationTest.java
rename to src/test/java/features/CucumberIntegrationTest.java
index 88a7029..ec1ddaa 100644
--- a/src/test/java/feature/CucumberIntegrationTest.java
+++ b/src/test/java/features/CucumberIntegrationTest.java
@@ -1,4 +1,4 @@
-package feature;
+package features;
import org.junit.platform.suite.api.ConfigurationParameter;
import org.junit.platform.suite.api.IncludeEngines;
@@ -11,7 +11,7 @@
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("features")
-@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "feature")
+@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "features")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
public class CucumberIntegrationTest {
diff --git a/src/test/java/feature/CucumberTypeConfig.java b/src/test/java/features/CucumberTypeConfig.java
similarity index 86%
rename from src/test/java/feature/CucumberTypeConfig.java
rename to src/test/java/features/CucumberTypeConfig.java
index c89ab6d..e539219 100644
--- a/src/test/java/feature/CucumberTypeConfig.java
+++ b/src/test/java/features/CucumberTypeConfig.java
@@ -1,6 +1,6 @@
-package feature;
+package features;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserRequestDTO;
import io.cucumber.java.DataTableType;
import java.util.List;
@@ -33,12 +33,12 @@ public FieldAssertion fieldAssertion(List row) {
}
/**
- * Convertit une ligne de DataTable (Map) en UserRequest.
+ * Convertit une ligne de DataTable (Map) en UserRequestDTO.
* Utilisable dans les .feature avec des tables à en-têtes.
*/
@DataTableType
- public UserRequest userRequest(Map row) {
- return new UserRequest(
+ public UserRequestDTO userRequest(Map row) {
+ return new UserRequestDTO(
row.get("gender"),
row.get("firstname"),
row.get("lastname"),
diff --git a/src/test/java/feature/SpringIntegrationTest.java b/src/test/java/features/SpringIntegrationTest.java
similarity index 99%
rename from src/test/java/feature/SpringIntegrationTest.java
rename to src/test/java/features/SpringIntegrationTest.java
index a3d8d66..66a6495 100644
--- a/src/test/java/feature/SpringIntegrationTest.java
+++ b/src/test/java/features/SpringIntegrationTest.java
@@ -1,4 +1,4 @@
-package feature;
+package features;
import com.xpeho.spring_boot_java_random_user.SpringBootJavaRandomUserApplication;
import io.cucumber.spring.CucumberContextConfiguration;
diff --git a/src/test/java/feature/StepDefinition.java b/src/test/java/features/StepDefinition.java
similarity index 94%
rename from src/test/java/feature/StepDefinition.java
rename to src/test/java/features/StepDefinition.java
index afb3443..c2e7e66 100644
--- a/src/test/java/feature/StepDefinition.java
+++ b/src/test/java/features/StepDefinition.java
@@ -1,9 +1,9 @@
-package feature;
+package features;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.xpeho.spring_boot_java_random_user.domain.entities.UserRequest;
-import feature.CucumberTypeConfig.FieldAssertion;
+import com.xpeho.spring_boot_java_random_user.presentation.dto.UserRequestDTO;
+import features.CucumberTypeConfig.FieldAssertion;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
@@ -18,12 +18,12 @@
public class StepDefinition extends SpringIntegrationTest {
private final ObjectMapper objectMapper = new ObjectMapper();
- private UserRequest payload;
+ private UserRequestDTO payload;
private Long createdUserId;
@Given("a valid user payload for creation")
public void aValidUserPayloadForCreation() {
- payload = new UserRequest(
+ payload = new UserRequestDTO(
"female",
"Emma",
"Stone",
@@ -102,7 +102,7 @@ public void theClientCallToDeleteTheCreatedUser() {
@Given("a valid user payload for update")
public void aValidUserPayloadForUpdate() {
- payload = new UserRequest(
+ payload = new UserRequestDTO(
"male",
"John",
"Doe",