feat: add ExpenseListController validation and authorization tests
This commit is contained in:
@@ -19,7 +19,7 @@ import de.zendric.app.xpensely_server.services.UserService;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/expenselist")
|
@RequestMapping("/api/expenselist")
|
||||||
class ExpenseListController {
|
public class ExpenseListController {
|
||||||
|
|
||||||
private final ExpenseListService expenseListService;
|
private final ExpenseListService expenseListService;
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
package de.zendric.app.xpensely_Server.controller;
|
||||||
|
|
||||||
|
import de.zendric.app.xpensely_server.controller.ExpenseListController;
|
||||||
|
import de.zendric.app.xpensely_server.model.AppUser;
|
||||||
|
import de.zendric.app.xpensely_server.model.ExpenseList;
|
||||||
|
import de.zendric.app.xpensely_server.security.AuthenticatedUserResolver;
|
||||||
|
import de.zendric.app.xpensely_server.services.CategoryService;
|
||||||
|
import de.zendric.app.xpensely_server.services.ExpenseListService;
|
||||||
|
import de.zendric.app.xpensely_server.services.UserService;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@WebMvcTest(ExpenseListController.class)
|
||||||
|
@AutoConfigureMockMvc(addFilters = false)
|
||||||
|
@ActiveProfiles("test")
|
||||||
|
class ExpenseListControllerTest {
|
||||||
|
|
||||||
|
@Autowired MockMvc mockMvc;
|
||||||
|
@MockitoBean ExpenseListService expenseListService;
|
||||||
|
@MockitoBean UserService userService;
|
||||||
|
@MockitoBean CategoryService categoryService;
|
||||||
|
@MockitoBean AuthenticatedUserResolver authenticatedUserResolver;
|
||||||
|
|
||||||
|
// --- Validation tests ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addExpense_blankTitle_returns400() throws Exception {
|
||||||
|
mockMvc.perform(post("/api/expenselist/1/add")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"title\":\"\",\"owner\":\"alice\",\"amount\":10.0,\"date\":\"2026-05-04\",\"category\":\"Food\"}"))
|
||||||
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.title").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addExpense_negativeAmount_returns400() throws Exception {
|
||||||
|
mockMvc.perform(post("/api/expenselist/1/add")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"title\":\"Lunch\",\"owner\":\"alice\",\"amount\":-5.0,\"date\":\"2026-05-04\",\"category\":\"Food\"}"))
|
||||||
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.amount").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addExpense_nullDate_returns400() throws Exception {
|
||||||
|
mockMvc.perform(post("/api/expenselist/1/add")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"title\":\"Lunch\",\"owner\":\"alice\",\"amount\":10.0,\"category\":\"Food\"}"))
|
||||||
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.date").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void acceptInvite_blankCode_returns400() throws Exception {
|
||||||
|
mockMvc.perform(post("/api/expenselist/accept-invite")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"inviteCode\":\"\"}"))
|
||||||
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.inviteCode").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void acceptInvite_wrongCodeLength_returns400() throws Exception {
|
||||||
|
mockMvc.perform(post("/api/expenselist/accept-invite")
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content("{\"inviteCode\":\"ABC\"}"))
|
||||||
|
.andExpect(status().isBadRequest())
|
||||||
|
.andExpect(jsonPath("$.inviteCode").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Authorization tests ---
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getById_authenticatedUserNotMember_returns403() throws Exception {
|
||||||
|
AppUser owner = new AppUser(); owner.setId(1L);
|
||||||
|
AppUser requester = new AppUser(); requester.setId(2L);
|
||||||
|
ExpenseList list = new ExpenseList(); list.setId(1L); list.setOwner(owner);
|
||||||
|
|
||||||
|
when(expenseListService.findById(1L)).thenReturn(Optional.of(list));
|
||||||
|
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(requester);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/expenselist/byId").param("id", "1"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getById_authenticatedUserIsOwner_returns200() throws Exception {
|
||||||
|
AppUser owner = new AppUser(); owner.setId(1L);
|
||||||
|
ExpenseList list = new ExpenseList(); list.setId(1L); list.setOwner(owner);
|
||||||
|
|
||||||
|
when(expenseListService.findById(1L)).thenReturn(Optional.of(list));
|
||||||
|
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(owner);
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/expenselist/byId").param("id", "1"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteList_nonOwner_returns403() throws Exception {
|
||||||
|
AppUser owner = new AppUser(); owner.setId(1L);
|
||||||
|
AppUser nonOwner = new AppUser(); nonOwner.setId(2L);
|
||||||
|
ExpenseList list = new ExpenseList(); list.setId(5L); list.setOwner(owner);
|
||||||
|
|
||||||
|
when(expenseListService.findById(5L)).thenReturn(Optional.of(list));
|
||||||
|
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(nonOwner);
|
||||||
|
|
||||||
|
mockMvc.perform(delete("/api/expenselist/5"))
|
||||||
|
.andExpect(status().isForbidden());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getMine_returnsCurrentUserLists() throws Exception {
|
||||||
|
AppUser user = new AppUser(); user.setId(3L);
|
||||||
|
|
||||||
|
when(authenticatedUserResolver.resolveCurrentUser(any())).thenReturn(user);
|
||||||
|
when(expenseListService.findByUserId(3L)).thenReturn(List.of(new ExpenseList()));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/expenselist/mine"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user