I am using Spring Boot 3 and have two entities: "Event" and "User". The relationship between these entities is many-to-many. A user can add many events, and an event can have many users.
I created simple Spring Boot endpoints but encountered a 404 error when testing with JUnit on the controller layer. I verified all URL paths and they are correct, but I'm unsure of the issue. The code is as follows: ** Controller layer method** the be test :
@RestController
@RequestMapping("api/users")
@RequiredArgsConstructor
public class UsersController {
@PutMapping("/{user_id}/{event_id}")
public ResponseEntity assignUserToEvent(@PathVariable Integer user_id, @PathVariable Integer event_id){
usersService.assignUserToEvent(user_id,event_id);
return ResponseEntity.status(200).body("User assigned to event successfully");
}
}
Service Layer of the method:
@Service
@RequiredArgsConstructor
public class UsersService {
private final UsersRepository usersRepository;
private final EventsRepositry eventsRepositry;
public void assignUserToEvent(Integer user_id, Integer event_id){
Users users = usersRepository.findUsersById(user_id);
Events event = eventsRepositry.findEventsById(event_id);
if (users == null|| event == null)
throw new ApiException("Sorry can't find the user or event");
if (!(event.getUsers() ==null)){
for (int i = 0; i < event.getUsers().size(); i++){ // a user should not be added twice
if (event.getUsers().get(i).getId() == user_id)
throw new ApiException("You already enrolled to this event");
}
}
if (!(users.getEvents()== null)){
for (int i =0 ; i < users.getEvents().size() ; i++){ // a user should not be added to an event cross with other event
Events currentEvent = eventsRepositry.findEventsById(users.getEvents().get(i).getId());
if(event.getDate().isEqual(currentEvent.getDate())){
if (event.getStartTime().equals(currentEvent.getStartTime())
|| (event.getStartTime().isAfter(currentEvent.getStartTime()) && event.getEndTime().isBefore(currentEvent.getEndTime()))
|| (event.getStartTime().isBefore(currentEvent.getEndTime()) && event.getEndTime().isAfter(currentEvent.getEndTime())
|| (event.getStartTime().isBefore(currentEvent.getStartTime()) && event.getEndTime().isAfter(currentEvent.getStartTime())) ) )
throw new ApiException("You Can't enroll to this event because it conflict with : "+ currentEvent.getName());
}
}
}
if(event.getDate().isEqual(LocalDate.now()) && event.getStartTime().isBefore(LocalTime.now())) // a user should not be added to an event past it's start time
throw new ApiException("Sorry you can't enroll to the "+event.getName() +" because it started");
users.getEvents().add(event);
usersRepository.save(users);
}
}
**Model of the user.java, and events.java **both these class have a M:M relationship user.java model
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Size(min = 2 , max = 20)
@Column(columnDefinition = "varchar(20)")
private String name;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "Events_Users_Table",
joinColumns = {
@JoinColumn(name = "user_id",referencedColumnName = "id")
},
inverseJoinColumns = {
@JoinColumn(name = "event_id", referencedColumnName = "id")
})
private List<Events> events;
}
**event.java model **
@Entity
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Events {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String location;
private String description;
private Integer attendees;
private LocalDate date;
private LocalTime startTime;
private LocalTime endTime;
@ManyToMany(mappedBy = "events",fetch = FetchType.LAZY)
@JsonIgnore
private List<Users> users;
}
And the last one is the method that i want test but 404 error appeared
@Test
public void assignUserToEventTest() throws Exception {
mockMvc.perform(put("/api/users/{user_id}/{event_id}",user1.getId(), event1.getId()))
@AutoConfigureMockMvc(addFilters = false)
@ExtendWith(SpringExtension.class)
@WebMvcTest(value = UsersController.class,excludeAutoConfiguration = {SecurityAutoConfiguration.class})
public class UserControllerTest {
@MockBean
UsersService usersService;
@MockBean
EventsService eventsService;
@Autowired
MockMvc mockMvc;
Users user1;
Events event1,event2;
List<Users> users;
List<Events> events;
@BeforeEach
void setUp(){
user1 = new Users(null, "Reham Sayer",null);
event1 = new Events(null, "Event Test 1", "Riyadh", "Event Test Example",3, LocalDate.of(2024,2,20), LocalTime.of(14,00,00),LocalTime.of(16,00,00),null);
event2 = new Events(null, "Event Test 2", "Riyadh", "Event Test Example",3, LocalDate.of(2024,3,20), LocalTime.of(14,00,00),LocalTime.of(16,00,00),null);
events = new ArrayList<>();
events.add(event1);
users= new ArrayList<>();
users.add(user1);
} .andExpect(status().isOk());
@Test
public void assignUserToEventTest() throws Exception {
mockMvc.perform(put("/api/users/{user_id}/{event_id}",user1.getId(), event1.getId()))
.andExpect(status().isOk());
}
}
I attempted to change the URL several times and tested it again, but the same issue persisted. Additionally, I believe the problem lies in the relationship between the user and the event, though I cannot confirm this.