You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

135 lines
6.6 KiB

package com.mydreamjob.review;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
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.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import java.util.List;
import java.util.Map;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("integration-test")
class JobReviewControllerTest {
@Autowired private MockMvc mockMvc;
@Autowired private com.mydreamjob.auth.JwtTokenProvider jwtTokenProvider;
@MockBean private JobReviewService reviewService;
@MockBean private RedisTemplate<String, Object> redisTemplate;
private final ObjectMapper mapper = new ObjectMapper();
private static final Long JOB_ID = 10L;
private static final Long REVIEW_ID = 1L;
@BeforeEach
@SuppressWarnings("unchecked")
void setUp() {
ValueOperations<String, Object> ops = mock(ValueOperations.class);
when(redisTemplate.opsForValue()).thenReturn(ops);
when(redisTemplate.hasKey(any())).thenReturn(false);
}
private String token() {
return "Bearer " + jwtTokenProvider.generateAccessToken(100L, "1",
java.util.Map.of("roles", "STUDENT"));
}
@Test void createReview_shouldReturn200() throws Exception {
when(reviewService.createReview(eq(100L), eq(JOB_ID), any(), any()))
.thenReturn(Map.of("id", 1, "rating", 4));
String body = mapper.writeValueAsString(Map.of("rating", 4, "content", "ok"));
mockMvc.perform(post("/jobs/" + JOB_ID + "/reviews")
.header("Authorization", token()).contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.rating").value(4));
}
@Test void createReview_noToken_shouldReturn401() throws Exception {
String body = mapper.writeValueAsString(Map.of("rating", 4, "content", "ok"));
mockMvc.perform(post("/jobs/" + JOB_ID + "/reviews")
.contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isUnauthorized());
}
@Test void listReviews_public_shouldReturn200() throws Exception {
when(reviewService.listReviews(eq(JOB_ID), any(), any(), any(), anyBoolean(), eq(0), eq(20)))
.thenReturn(new PageImpl<>(List.of(Map.of("rating", 4))));
mockMvc.perform(get("/jobs/" + JOB_ID + "/reviews"))
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
}
@Test void updateReview_shouldReturn200() throws Exception {
when(reviewService.updateReview(eq(100L), eq(JOB_ID), eq(REVIEW_ID), any(), any()))
.thenReturn(Map.of("id", 1, "rating", 5));
String body = mapper.writeValueAsString(Map.of("rating", 5, "content", "updated"));
mockMvc.perform(put("/jobs/" + JOB_ID + "/reviews/" + REVIEW_ID)
.header("Authorization", token()).contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isOk()).andExpect(jsonPath("$.data.rating").value(5));
}
@Test void deleteReview_shouldReturn200() throws Exception {
doNothing().when(reviewService).deleteReview(eq(100L), eq(JOB_ID), eq(REVIEW_ID), any());
mockMvc.perform(delete("/jobs/" + JOB_ID + "/reviews/" + REVIEW_ID)
.header("Authorization", token()))
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200));
}
@Test void createReview_invalidRating_shouldReturn400() throws Exception {
String body = mapper.writeValueAsString(Map.of("rating", 6, "content", "ok"));
mockMvc.perform(post("/jobs/" + JOB_ID + "/reviews")
.header("Authorization", token()).contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isBadRequest());
}
@Test void createReview_blankContent_shouldReturn400() throws Exception {
String body = mapper.writeValueAsString(Map.of("rating", 4, "content", ""));
mockMvc.perform(post("/jobs/" + JOB_ID + "/reviews")
.header("Authorization", token()).contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isBadRequest());
}
@Test void updateReview_invalidStatus_shouldReturn400() throws Exception {
String body = mapper.writeValueAsString(Map.of("status", "INVALID"));
mockMvc.perform(put("/jobs/" + JOB_ID + "/reviews/" + REVIEW_ID)
.header("Authorization", token()).contentType(MediaType.APPLICATION_JSON).content(body))
.andExpect(status().isBadRequest());
}
@Test void summary_public_shouldReturn200() throws Exception {
when(reviewService.getReviewSummary(JOB_ID)).thenReturn(Map.of(
"jobId", JOB_ID, "totalReviews", 2, "averageRating", 4.5,
"ratingDistribution", Map.of("rating1",0,"rating2",0,"rating3",0,"rating4",1,"rating5",1),
"topTags", List.of("tag1")));
mockMvc.perform(get("/jobs/" + JOB_ID + "/reviews/summary"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.data.averageRating").value(4.5))
.andExpect(jsonPath("$.data.totalReviews").value(2));
}
@Test void summary_noReviews_shouldReturnZeros() throws Exception {
when(reviewService.getReviewSummary(JOB_ID)).thenReturn(Map.of(
"jobId", JOB_ID, "totalReviews", 0, "averageRating", 0.0,
"ratingDistribution", Map.of("rating1",0,"rating2",0,"rating3",0,"rating4",0,"rating5",0),
"topTags", List.of()));
mockMvc.perform(get("/jobs/" + JOB_ID + "/reviews/summary"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.totalReviews").value(0));
}
}