Skip to content

Commit 5e8342d

Browse files
authored
Merge pull request #18 from java-backend-foundations/feature/4-services-tests
Services testcases added
2 parents aef67c6 + d63196a commit 5e8342d

File tree

2 files changed

+355
-0
lines changed

2 files changed

+355
-0
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package com.capgemini.training.appointmentbooking.service.impl;
2+
3+
import static org.hamcrest.Matchers.is;
4+
import static org.hamcrest.Matchers.notNullValue;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.Mockito.when;
7+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
8+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
9+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
10+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
11+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
12+
13+
import com.capgemini.training.appointmentbooking.common.BaseTest;
14+
import com.capgemini.training.appointmentbooking.common.datatype.AppointmentStatus;
15+
import com.capgemini.training.appointmentbooking.common.to.AppointmentCto;
16+
import com.capgemini.training.appointmentbooking.common.to.AppointmentEto;
17+
import com.capgemini.training.appointmentbooking.common.to.ClientEto;
18+
import com.capgemini.training.appointmentbooking.common.to.TreatmentCto;
19+
import com.capgemini.training.appointmentbooking.common.to.TreatmentEto;
20+
import com.capgemini.training.appointmentbooking.dataaccess.repository.criteria.AppointmentCriteria;
21+
import com.capgemini.training.appointmentbooking.logic.FindAppointmentUc;
22+
import com.capgemini.training.appointmentbooking.logic.ManageAppointmentUc;
23+
import com.capgemini.training.appointmentbooking.service.config.ServiceMappingConfiguration;
24+
import com.capgemini.training.appointmentbooking.service.model.AppointmentRequest;
25+
import com.capgemini.training.appointmentbooking.service.model.AppointmentStatusUpdate;
26+
import com.capgemini.training.appointmentbooking.service.model.AppointmentStatusUpdate.StatusEnum;
27+
import com.fasterxml.jackson.databind.ObjectMapper;
28+
import java.time.Instant;
29+
import java.util.Collections;
30+
import java.util.Date;
31+
import java.util.List;
32+
import org.junit.jupiter.api.Test;
33+
import org.springframework.beans.factory.annotation.Autowired;
34+
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
35+
import org.springframework.context.annotation.Import;
36+
import org.springframework.http.MediaType;
37+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
38+
import org.springframework.test.web.servlet.MockMvc;
39+
40+
@WebMvcTest(controllers = AppointmentsApiController.class)
41+
@Import(ServiceMappingConfiguration.class)
42+
public class AppointmentsApiControllerTest extends BaseTest {
43+
44+
@Autowired private MockMvc mockMvc;
45+
46+
@MockitoBean private FindAppointmentUc findAppointmentUc;
47+
48+
@MockitoBean private ManageAppointmentUc manageAppointmentUc;
49+
50+
@Autowired private ObjectMapper objectMapper;
51+
52+
@Test
53+
void shouldCreateAppointmentAndReturn201() throws Exception {
54+
Instant now = Instant.now();
55+
AppointmentRequest request = createAppointmentRequest(1L, 2L, now);
56+
AppointmentCto appointmentCto =
57+
createAppointmentCto(1L, now, AppointmentStatus.SCHEDULED, 1L, 2L, "Cleaning");
58+
59+
when(manageAppointmentUc.bookAppointment(any())).thenReturn(appointmentCto);
60+
61+
mockMvc
62+
.perform(
63+
post("/api/v1/appointments")
64+
.contentType(MediaType.APPLICATION_JSON)
65+
.content(objectMapper.writeValueAsString(request)))
66+
.andExpect(status().isCreated())
67+
.andExpect(jsonPath("$.id").value(1))
68+
.andExpect(jsonPath("$.status").value(AppointmentStatus.SCHEDULED.name()))
69+
.andExpect(jsonPath("$.dateTime", notNullValue()))
70+
.andExpect(jsonPath("$.clientId").value(1))
71+
.andExpect(jsonPath("$.treatmentId").value(2));
72+
}
73+
74+
@Test
75+
void shouldReturn400WhenCreatingAppointmentWithInvalidPayload() throws Exception {
76+
mockMvc
77+
.perform(
78+
post("/api/v1/appointments")
79+
.contentType(MediaType.APPLICATION_JSON)
80+
.content("{ \"specialistId\" : \"abc\" }"))
81+
.andExpect(status().isBadRequest());
82+
}
83+
84+
@Test
85+
void shouldReturnAppointmentsListWith200() throws Exception {
86+
Instant now = Instant.now();
87+
AppointmentCto appointmentCto =
88+
createAppointmentCto(1L, now, AppointmentStatus.SCHEDULED, 1L, 2L, "Filling");
89+
90+
when(findAppointmentUc.findByCriteria(any())).thenReturn(List.of(appointmentCto));
91+
92+
mockMvc
93+
.perform(get("/api/v1/appointments"))
94+
.andExpect(status().isOk())
95+
.andExpect(jsonPath("$[0].id").value(1))
96+
.andExpect(jsonPath("$[0].status").value(AppointmentStatus.SCHEDULED.name()))
97+
.andExpect(jsonPath("$[0].clientId").value(1))
98+
.andExpect(jsonPath("$[0].treatmentId").value(2));
99+
}
100+
101+
@Test
102+
void shouldReturnAppointmentsListWith200Filtered() throws Exception {
103+
Instant now = Instant.now();
104+
AppointmentCto appointmentCto =
105+
createAppointmentCto(1L, now, AppointmentStatus.SCHEDULED, 1L, 2L, "Filling");
106+
107+
when(findAppointmentUc.findByCriteria(
108+
AppointmentCriteria.builder().status(AppointmentStatus.SCHEDULED).build()))
109+
.thenReturn(List.of(appointmentCto));
110+
when(findAppointmentUc.findByCriteria(
111+
AppointmentCriteria.builder().status(AppointmentStatus.CANCELLED).build()))
112+
.thenReturn(List.of());
113+
114+
mockMvc
115+
.perform(get("/api/v1/appointments").param("status", AppointmentStatus.SCHEDULED.name()))
116+
.andExpect(status().isOk())
117+
.andExpect(jsonPath("$[0].id").value(1))
118+
.andExpect(jsonPath("$[0].status").value(AppointmentStatus.SCHEDULED.name()))
119+
.andExpect(jsonPath("$[0].clientId").value(1))
120+
.andExpect(jsonPath("$[0].treatmentId").value(2));
121+
122+
mockMvc
123+
.perform(get("/api/v1/appointments").param("status", AppointmentStatus.CANCELLED.name()))
124+
.andExpect(status().isOk())
125+
.andExpect(jsonPath("$.length()", is(0)));
126+
}
127+
128+
@Test
129+
void shouldReturnEmptyListWhenNoAppointmentsExist() throws Exception {
130+
when(findAppointmentUc.findAll()).thenReturn(Collections.emptyList());
131+
132+
mockMvc
133+
.perform(get("/api/v1/appointments"))
134+
.andExpect(status().isOk())
135+
.andExpect(jsonPath("$.length()", is(0)));
136+
}
137+
138+
@Test
139+
void shouldUpdateAppointmentStatusAndReturn200() throws Exception {
140+
AppointmentStatusUpdate update = new AppointmentStatusUpdate();
141+
update.setStatus(StatusEnum.CANCELLED);
142+
143+
mockMvc
144+
.perform(
145+
patch("/api/v1/appointments/1")
146+
.contentType(MediaType.APPLICATION_JSON)
147+
.content(objectMapper.writeValueAsString(update)))
148+
.andExpect(status().isOk());
149+
}
150+
151+
@Test
152+
void shouldReturn400WhenUpdatingAppointmentWithInvalidStatus() throws Exception {
153+
String invalidJson = "{ \"status\": \"INVALID\" }";
154+
155+
mockMvc
156+
.perform(
157+
patch("/api/v1/appointments/1")
158+
.contentType(MediaType.APPLICATION_JSON)
159+
.content(invalidJson))
160+
.andExpect(status().isBadRequest());
161+
}
162+
163+
@Test
164+
void shouldReturnAvailabilityStatusWith200() throws Exception {
165+
String date = "2024-12-12T10:15:30Z";
166+
when(findAppointmentUc.hasConflictingAppointment(1L, Instant.parse(date))).thenReturn(false);
167+
168+
mockMvc
169+
.perform(get("/api/v1/availability").param("specialistId", "1").param("dateTime", date))
170+
.andExpect(status().isOk())
171+
.andExpect(jsonPath("$.available", is(true)));
172+
}
173+
174+
@Test
175+
void shouldReturn400WhenAvailabilityQueryIsMissingParams() throws Exception {
176+
mockMvc.perform(get("/api/v1/availability")).andExpect(status().isBadRequest());
177+
}
178+
179+
// ======= HELPER METHODS =======
180+
181+
private AppointmentRequest createAppointmentRequest(
182+
Long clientId, Long treatmentId, Instant dateTime) {
183+
AppointmentRequest request = new AppointmentRequest();
184+
request.setClientId(clientId);
185+
request.setTreatmentId(treatmentId);
186+
request.setDateTime(Date.from(dateTime));
187+
return request;
188+
}
189+
190+
private AppointmentCto createAppointmentCto(
191+
Long appointmentId,
192+
Instant dateTime,
193+
AppointmentStatus status,
194+
Long clientId,
195+
Long treatmentId,
196+
String treatmentName) {
197+
return AppointmentCto.builder()
198+
.appointmentEto(
199+
AppointmentEto.builder().id(appointmentId).dateTime(dateTime).status(status).build())
200+
.clientEto(ClientEto.builder().id(clientId).build())
201+
.treatmentCto(
202+
TreatmentCto.builder()
203+
.treatmentEto(TreatmentEto.builder().id(treatmentId).name(treatmentName).build())
204+
.build())
205+
.build();
206+
}
207+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package com.capgemini.training.appointmentbooking.service.impl;
2+
3+
import static org.hamcrest.Matchers.is;
4+
import static org.mockito.ArgumentMatchers.any;
5+
import static org.mockito.Mockito.when;
6+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
7+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
8+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
9+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
10+
11+
import com.capgemini.training.appointmentbooking.common.BaseTest;
12+
import com.capgemini.training.appointmentbooking.common.datatype.Specialization;
13+
import com.capgemini.training.appointmentbooking.common.to.SpecialistEto;
14+
import com.capgemini.training.appointmentbooking.common.to.TreatmentCto;
15+
import com.capgemini.training.appointmentbooking.common.to.TreatmentEto;
16+
import com.capgemini.training.appointmentbooking.logic.FindTreatmentUc;
17+
import com.capgemini.training.appointmentbooking.logic.ManageTreatmentUc;
18+
import com.capgemini.training.appointmentbooking.service.config.ServiceMappingConfiguration;
19+
import com.capgemini.training.appointmentbooking.service.model.TreatmentRequest;
20+
import com.fasterxml.jackson.databind.ObjectMapper;
21+
import java.util.List;
22+
import java.util.Optional;
23+
import org.junit.jupiter.api.Test;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
26+
import org.springframework.context.annotation.Import;
27+
import org.springframework.http.MediaType;
28+
import org.springframework.test.context.bean.override.mockito.MockitoBean;
29+
import org.springframework.test.web.servlet.MockMvc;
30+
31+
@WebMvcTest(controllers = TreatmentsApiController.class)
32+
@Import(ServiceMappingConfiguration.class)
33+
public class TreatmentsApiControllerTest extends BaseTest {
34+
@Autowired private MockMvc mockMvc;
35+
36+
@MockitoBean private FindTreatmentUc findTreatmentUc;
37+
38+
@MockitoBean private ManageTreatmentUc manageTreatmentUc;
39+
40+
@Autowired private ObjectMapper objectMapper;
41+
42+
@Test
43+
void shouldCreateTreatmentAndReturn201() throws Exception {
44+
// given
45+
String name = "Test name";
46+
int duration = 30;
47+
Long specialistId = 101L;
48+
49+
TreatmentRequest request = createTreatmentRequest(name, duration, specialistId);
50+
TreatmentCto treatmentCto =
51+
createTreatmentCto(1L, name, duration, specialistId, Specialization.DENTIST);
52+
53+
when(manageTreatmentUc.createTreatment(any())).thenReturn(treatmentCto);
54+
55+
// when / then
56+
mockMvc
57+
.perform(
58+
post("/api/v1/treatments")
59+
.contentType(MediaType.APPLICATION_JSON)
60+
.content(objectMapper.writeValueAsString(request)))
61+
.andExpect(status().isCreated())
62+
.andExpect(jsonPath("$.name", is(name)))
63+
.andExpect(jsonPath("$.duration", is(duration)))
64+
.andExpect(jsonPath("$.specialistId").value(specialistId));
65+
}
66+
67+
@Test
68+
void shouldReturn400OnInvalidTreatmentRequest() throws Exception {
69+
// given – invalid JSON (wrong type)
70+
String invalidJson = "{ \"specialistId\" : \"abc\" }";
71+
72+
// when / then
73+
mockMvc
74+
.perform(
75+
post("/api/v1/treatments").contentType(MediaType.APPLICATION_JSON).content(invalidJson))
76+
.andExpect(status().isBadRequest());
77+
}
78+
79+
@Test
80+
void shouldReturnTreatmentsListWith200() throws Exception {
81+
// given
82+
String name = "Treatment A";
83+
int duration = 45;
84+
Long specialistId = 123L;
85+
86+
TreatmentCto treatmentCto =
87+
createTreatmentCto(1L, name, duration, specialistId, Specialization.DENTIST);
88+
when(findTreatmentUc.findAll()).thenReturn(List.of(treatmentCto));
89+
90+
// when / then
91+
mockMvc
92+
.perform(get("/api/v1/treatments"))
93+
.andExpect(status().isOk())
94+
.andExpect(jsonPath("$[0].name", is(name)))
95+
.andExpect(jsonPath("$[0].duration", is(duration)))
96+
.andExpect(jsonPath("$[0].specialistId").value(specialistId));
97+
}
98+
99+
@Test
100+
void shouldReturnTreatmentDetailsWith200WhenFound() throws Exception {
101+
// given
102+
Long treatmentId = 101L;
103+
String name = "Test treatment";
104+
int duration = 30;
105+
Long specialistId = 101L;
106+
107+
TreatmentCto treatmentCto =
108+
createTreatmentCto(treatmentId, name, duration, specialistId, Specialization.DENTIST);
109+
when(findTreatmentUc.findById(treatmentId)).thenReturn(Optional.of(treatmentCto));
110+
111+
// when / then
112+
mockMvc
113+
.perform(get("/api/v1/treatments/" + treatmentId))
114+
.andExpect(status().isOk())
115+
.andExpect(jsonPath("$.name", is(name)))
116+
.andExpect(jsonPath("$.duration", is(duration)))
117+
.andExpect(jsonPath("$.specialistId").value(specialistId))
118+
.andExpect(jsonPath("$.specialist.name", is(Specialization.DENTIST.name())));
119+
}
120+
121+
@Test
122+
void shouldReturn404WhenTreatmentNotFound() throws Exception {
123+
// given
124+
Long treatmentId = 101L;
125+
126+
when(findTreatmentUc.findById(treatmentId)).thenReturn(Optional.empty());
127+
128+
// when / then
129+
mockMvc.perform(get("/api/v1/treatments/" + treatmentId)).andExpect(status().isNotFound());
130+
}
131+
132+
private TreatmentRequest createTreatmentRequest(String name, int duration, Long specialistId) {
133+
TreatmentRequest request = new TreatmentRequest();
134+
request.setName(Optional.of(name));
135+
request.setDuration(Optional.of(duration));
136+
request.setSpecialistId(Optional.of(specialistId));
137+
return request;
138+
}
139+
140+
private TreatmentCto createTreatmentCto(
141+
Long id, String name, int duration, Long specialistId, Specialization specialization) {
142+
return TreatmentCto.builder()
143+
.specialistEto(
144+
SpecialistEto.builder().id(specialistId).specialization(specialization).build())
145+
.treatmentEto(TreatmentEto.builder().id(id).name(name).durationMinutes(duration).build())
146+
.build();
147+
}
148+
}

0 commit comments

Comments
 (0)