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.
470 lines
23 KiB
470 lines
23 KiB
package com.mydreamjob.offer;
|
|
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.mydreamjob.common.exception.BusinessException;
|
|
import com.mydreamjob.common.exception.ErrorCode;
|
|
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.Page;
|
|
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.nio.charset.StandardCharsets;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.ArgumentMatchers.isNull;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
|
|
/**
|
|
* Offer 接口集成测试:JWT 鉴权、统一响应结构、权限、业务错误、OpenAPI 一致性。
|
|
* 激活 profile: integration-test(H2 内嵌数据库 + Flyway V13 + Redis/Rabbit 关闭)
|
|
*/
|
|
@SpringBootTest
|
|
@AutoConfigureMockMvc
|
|
@ActiveProfiles("integration-test")
|
|
class OfferControllerTest {
|
|
|
|
@Autowired private MockMvc mockMvc;
|
|
@Autowired private com.mydreamjob.auth.JwtTokenProvider jwtTokenProvider;
|
|
@MockBean private OfferService offerService;
|
|
@MockBean private RedisTemplate<String, Object> redisTemplate;
|
|
|
|
private final ObjectMapper mapper = new ObjectMapper();
|
|
|
|
private static final Long COMPANY_USER_ID = 10L;
|
|
private static final Long STUDENT_ID = 100L;
|
|
private static final Long OFFER_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 companyToken() {
|
|
return com.mydreamjob.auth.support.TestAuthTokens.bearer(COMPANY_USER_ID, "COMPANY");
|
|
}
|
|
|
|
private String studentToken() {
|
|
return com.mydreamjob.auth.support.TestAuthTokens.bearer(STUDENT_ID, "STUDENT");
|
|
}
|
|
|
|
private Map<String, Object> offerView() {
|
|
return Map.of("id", OFFER_ID, "applicationId", 5L, "jobId", 10L,
|
|
"companyId", 1L, "candidateId", STUDENT_ID, "title", "后端工程师",
|
|
"status", "DRAFT", "salaryMin", 10000, "salaryMax", 20000);
|
|
}
|
|
|
|
private void stubOfferView() {
|
|
when(offerService.toView(any())).thenReturn(offerView());
|
|
}
|
|
|
|
private String createBody() {
|
|
return """
|
|
{
|
|
"applicationId": 5,
|
|
"title": "后端工程师",
|
|
"salaryMin": 10000,
|
|
"salaryMax": 20000,
|
|
"workCity": "杭州",
|
|
"description": "负责服务端开发",
|
|
"expireAt": "2030-12-31T23:59:59"
|
|
}
|
|
""";
|
|
}
|
|
|
|
// ── 创建 ──────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void create_shouldReturn200WithUnifiedResponse() throws Exception {
|
|
stubOfferView();
|
|
when(offerService.createOffer(eq(COMPANY_USER_ID), any(), any())).thenReturn(Offer.builder().id(OFFER_ID).build());
|
|
mockMvc.perform(post("/offers")
|
|
.header("Authorization", companyToken())
|
|
.header("X-Request-Id", "req-abc")
|
|
.contentType(MediaType.APPLICATION_JSON).content(createBody()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.message").value("ok"))
|
|
.andExpect(jsonPath("$.data.id").value(OFFER_ID))
|
|
.andExpect(jsonPath("$.requestId").value("req-abc"))
|
|
.andExpect(jsonPath("$.timestamp").isNotEmpty());
|
|
}
|
|
|
|
@Test
|
|
void create_invalidBody_shouldReturn400() throws Exception {
|
|
mockMvc.perform(post("/offers")
|
|
.header("Authorization", companyToken())
|
|
.contentType(MediaType.APPLICATION_JSON).content("{}"))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(400));
|
|
}
|
|
|
|
@Test
|
|
void create_noToken_shouldReturn401() throws Exception {
|
|
mockMvc.perform(post("/offers")
|
|
.contentType(MediaType.APPLICATION_JSON).content(createBody()))
|
|
.andExpect(status().isUnauthorized())
|
|
.andExpect(jsonPath("$.code").value(401));
|
|
}
|
|
|
|
@Test
|
|
void create_byStudent_shouldReturn403() throws Exception {
|
|
when(offerService.createOffer(eq(STUDENT_ID), any(), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.FORBIDDEN));
|
|
mockMvc.perform(post("/offers")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON).content(createBody()))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
// ── 列表 ──────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void list_shouldReturn200WithPagination() throws Exception {
|
|
stubOfferView();
|
|
Page<Offer> page = new PageImpl<>(List.of(Offer.builder().id(OFFER_ID).build()),
|
|
org.springframework.data.domain.PageRequest.of(0, 20), 1);
|
|
when(offerService.listOffers(eq(STUDENT_ID), isNull(), isNull(), eq(0), eq(20))).thenReturn(page);
|
|
mockMvc.perform(get("/offers").header("Authorization", studentToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.items").isArray())
|
|
.andExpect(jsonPath("$.data.total").isNumber())
|
|
.andExpect(jsonPath("$.data.page").value(0))
|
|
.andExpect(jsonPath("$.data.size").value(20));
|
|
}
|
|
|
|
@Test
|
|
void list_noToken_shouldReturn401() throws Exception {
|
|
mockMvc.perform(get("/offers")).andExpect(status().isUnauthorized());
|
|
}
|
|
|
|
// ── 详情 ──────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void get_shouldReturn200() throws Exception {
|
|
stubOfferView();
|
|
when(offerService.getOffer(OFFER_ID, STUDENT_ID)).thenReturn(Offer.builder().id(OFFER_ID).build());
|
|
mockMvc.perform(get("/offers/" + OFFER_ID).header("Authorization", studentToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.status").value("DRAFT"));
|
|
}
|
|
|
|
@Test
|
|
void get_otherUser_shouldReturn403() throws Exception {
|
|
when(offerService.getOffer(OFFER_ID, STUDENT_ID))
|
|
.thenThrow(new BusinessException(ErrorCode.FORBIDDEN));
|
|
mockMvc.perform(get("/offers/" + OFFER_ID).header("Authorization", studentToken()))
|
|
.andExpect(status().isForbidden())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.FORBIDDEN.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void get_notFound_shouldReturn404() throws Exception {
|
|
when(offerService.getOffer(999L, STUDENT_ID))
|
|
.thenThrow(new BusinessException(ErrorCode.OFFER_NOT_FOUND));
|
|
mockMvc.perform(get("/offers/999").header("Authorization", studentToken()))
|
|
.andExpect(status().isNotFound())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.OFFER_NOT_FOUND.getCode()));
|
|
}
|
|
|
|
// ── 修改 ──────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void update_sentOffer_shouldReturn409() throws Exception {
|
|
when(offerService.updateOffer(eq(COMPANY_USER_ID), eq(OFFER_ID), any(), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.OFFER_NOT_EDITABLE));
|
|
mockMvc.perform(put("/offers/" + OFFER_ID)
|
|
.header("Authorization", companyToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"title\":\"新标题\"}"))
|
|
.andExpect(status().isConflict())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.OFFER_NOT_EDITABLE.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void update_draft_shouldReturn200() throws Exception {
|
|
stubOfferView();
|
|
when(offerService.updateOffer(eq(COMPANY_USER_ID), eq(OFFER_ID), any(), any()))
|
|
.thenReturn(Offer.builder().id(OFFER_ID).build());
|
|
mockMvc.perform(put("/offers/" + OFFER_ID)
|
|
.header("Authorization", companyToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"title\":\"新标题\"}"))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.data.title").value("后端工程师"));
|
|
}
|
|
|
|
// ── 状态变更 ──────────────────────────────────────────────
|
|
|
|
@Test
|
|
void changeStatus_shouldReturn200() throws Exception {
|
|
stubOfferView();
|
|
when(offerService.transitionStatus(eq(STUDENT_ID), eq(OFFER_ID), any(), any()))
|
|
.thenReturn(Offer.builder().id(OFFER_ID).build());
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/status")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"status\":\"ACCEPTED\"}"))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200));
|
|
}
|
|
|
|
@Test
|
|
void changeStatus_invalidTransition_shouldReturn409() throws Exception {
|
|
when(offerService.transitionStatus(eq(STUDENT_ID), eq(OFFER_ID), any(), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.INVALID_OFFER_STATUS_TRANSITION));
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/status")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"status\":\"REJECTED\"}"))
|
|
.andExpect(status().isConflict())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.INVALID_OFFER_STATUS_TRANSITION.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void changeStatus_invalidStatusValue_shouldReturn400() throws Exception {
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/status")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"status\":\"INVALID\"}"))
|
|
.andExpect(status().isBadRequest());
|
|
}
|
|
|
|
// ── 时间线 ────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void timeline_shouldReturn200() throws Exception {
|
|
when(offerService.getTimeline(OFFER_ID, STUDENT_ID)).thenReturn(List.of(
|
|
Map.of("fromStatus", "DRAFT", "toStatus", "SENT", "operatorRole", "COMPANY")));
|
|
mockMvc.perform(get("/offers/" + OFFER_ID + "/timeline").header("Authorization", studentToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.data[0].toStatus").value("SENT"));
|
|
}
|
|
|
|
// ── 提醒 ──────────────────────────────────────────────────
|
|
|
|
@Test
|
|
void remind_shouldReturn200() throws Exception {
|
|
OfferReminder reminder = OfferReminder.builder().offerId(OFFER_ID)
|
|
.reminderType(OfferReminder.TYPE_MANUAL).status(OfferReminder.STATUS_SENT).build();
|
|
when(offerService.remind(eq(COMPANY_USER_ID), eq(OFFER_ID), any())).thenReturn(reminder);
|
|
mockMvc.perform(post("/offers/" + OFFER_ID + "/remind").header("Authorization", companyToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.data.reminderType").value("MANUAL"))
|
|
.andExpect(jsonPath("$.code").value(200));
|
|
}
|
|
|
|
// ── OpenAPI 一致性 ────────────────────────────────────────
|
|
|
|
@Test
|
|
void openApi_shouldContainOfferEndpoints() throws Exception {
|
|
String json = mockMvc.perform(get("/v3/api-docs"))
|
|
.andExpect(status().isOk())
|
|
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|
JsonNode root = mapper.readTree(json);
|
|
JsonNode paths = root.path("paths");
|
|
assertThat(paths.has("/offers")).isTrue();
|
|
assertThat(paths.has("/offers/{id}")).isTrue();
|
|
assertThat(paths.has("/offers/{id}/status")).isTrue();
|
|
assertThat(paths.has("/offers/{id}/timeline")).isTrue();
|
|
assertThat(paths.has("/offers/{id}/remind")).isTrue();
|
|
// POST /offers 必须声明 POST 方法
|
|
assertTrue(paths.path("/offers").has("post"));
|
|
// GET /offers 必须声明 GET 方法
|
|
assertTrue(paths.path("/offers").has("get"));
|
|
// 开发辅助:当 -Doffer.openapi.snapshot=<目录> 时导出 OpenAPI 快照到 <目录>/openapi-rc.json
|
|
String snapshotDir = System.getProperty("offer.openapi.snapshot");
|
|
if (snapshotDir != null && !snapshotDir.isBlank()) {
|
|
java.nio.file.Files.write(
|
|
java.nio.file.Paths.get(snapshotDir, "openapi-rc.json"),
|
|
json.getBytes(StandardCharsets.UTF_8));
|
|
}
|
|
}
|
|
|
|
// ── Offer 进阶接口 ────────────────────────────────────────
|
|
|
|
@Test
|
|
void openApi_shouldContainNewOfferEndpoints() throws Exception {
|
|
String json = mockMvc.perform(get("/v3/api-docs"))
|
|
.andExpect(status().isOk())
|
|
.andReturn().getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|
JsonNode root = mapper.readTree(json);
|
|
JsonNode paths = root.path("paths");
|
|
assertThat(paths.has("/offers/{id}/counter-offers")).isTrue();
|
|
assertThat(paths.has("/offers/{id}/counter-offers/{coId}/accept")).isTrue();
|
|
assertThat(paths.has("/offers/{id}/counter-offers/{coId}/reject")).isTrue();
|
|
assertThat(paths.has("/offers/compare")).isTrue();
|
|
assertThat(paths.has("/offers/statistics")).isTrue();
|
|
}
|
|
|
|
@Test
|
|
void createCounterOffer_shouldReturn200() throws Exception {
|
|
Map<String, Object> coView = Map.of("id", 1L, "offerId", OFFER_ID, "status", "PENDING");
|
|
when(offerService.toCounterOfferView(any())).thenReturn(coView);
|
|
when(offerService.createCounterOffer(eq(STUDENT_ID), eq(OFFER_ID), any(), any()))
|
|
.thenReturn(OfferCounterOffer.builder().id(1L).build());
|
|
mockMvc.perform(post("/offers/" + OFFER_ID + "/counter-offers")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"proposedSalaryMin\":15000,\"proposedSalaryMax\":25000,\"reason\":\"期望薪资更高\"}"))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.status").value("PENDING"));
|
|
}
|
|
|
|
@Test
|
|
void createCounterOffer_notNegotiable_shouldReturn400() throws Exception {
|
|
when(offerService.createCounterOffer(eq(STUDENT_ID), eq(OFFER_ID), any(), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.OFFER_NOT_NEGOTIABLE));
|
|
mockMvc.perform(post("/offers/" + OFFER_ID + "/counter-offers")
|
|
.header("Authorization", studentToken())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content("{\"proposedSalaryMin\":15000,\"proposedSalaryMax\":25000}"))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.OFFER_NOT_NEGOTIABLE.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void listCounterOffers_shouldReturn200() throws Exception {
|
|
when(offerService.getCounterOffers(OFFER_ID, STUDENT_ID)).thenReturn(List.of());
|
|
mockMvc.perform(get("/offers/" + OFFER_ID + "/counter-offers")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200));
|
|
}
|
|
|
|
@Test
|
|
void acceptCounterOffer_shouldReturn200() throws Exception {
|
|
Map<String, Object> coView = Map.of("id", 1L, "status", "ACCEPTED");
|
|
when(offerService.toCounterOfferView(any())).thenReturn(coView);
|
|
when(offerService.acceptCounterOffer(eq(COMPANY_USER_ID), eq(OFFER_ID), eq(1L), any()))
|
|
.thenReturn(OfferCounterOffer.builder().id(1L).build());
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/counter-offers/1/accept")
|
|
.header("Authorization", companyToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.status").value("ACCEPTED"));
|
|
}
|
|
|
|
@Test
|
|
void acceptCounterOffer_notPending_shouldReturn409() throws Exception {
|
|
when(offerService.acceptCounterOffer(eq(COMPANY_USER_ID), eq(OFFER_ID), eq(1L), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.OFFER_COUNTER_OFFER_NOT_PENDING));
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/counter-offers/1/accept")
|
|
.header("Authorization", companyToken()))
|
|
.andExpect(status().isConflict())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.OFFER_COUNTER_OFFER_NOT_PENDING.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void rejectCounterOffer_shouldReturn200() throws Exception {
|
|
Map<String, Object> coView = Map.of("id", 1L, "status", "REJECTED");
|
|
when(offerService.toCounterOfferView(any())).thenReturn(coView);
|
|
when(offerService.rejectCounterOffer(eq(COMPANY_USER_ID), eq(OFFER_ID), eq(1L), any()))
|
|
.thenReturn(OfferCounterOffer.builder().id(1L).build());
|
|
mockMvc.perform(patch("/offers/" + OFFER_ID + "/counter-offers/1/reject")
|
|
.header("Authorization", companyToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.status").value("REJECTED"));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_shouldReturn200() throws Exception {
|
|
Map<String, Object> v = new java.util.HashMap<>(offerView());
|
|
v.put("companyName", "测试公司");
|
|
when(offerService.compareOffers(eq(STUDENT_ID), eq(List.of(1L, 2L))))
|
|
.thenReturn(List.of(v, v));
|
|
mockMvc.perform(get("/offers/compare?ids=1,2")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data[0].companyName").value("测试公司"));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_tooMany_shouldReturn400() throws Exception {
|
|
when(offerService.compareOffers(eq(STUDENT_ID), any()))
|
|
.thenThrow(new BusinessException(ErrorCode.OFFER_COMPARE_TOO_MANY));
|
|
mockMvc.perform(get("/offers/compare?ids=1")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.OFFER_COMPARE_TOO_MANY.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_nonNumeric_shouldReturn400() throws Exception {
|
|
mockMvc.perform(get("/offers/compare?ids=abc")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.BAD_REQUEST.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_emptyValue_shouldReturn400() throws Exception {
|
|
mockMvc.perform(get("/offers/compare?ids=1,,2")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.BAD_REQUEST.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_blank_shouldReturn400() throws Exception {
|
|
mockMvc.perform(get("/offers/compare?ids=")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.BAD_REQUEST.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void compareOffers_negative_shouldReturn400() throws Exception {
|
|
mockMvc.perform(get("/offers/compare?ids=1,-2")
|
|
.header("Authorization", studentToken()))
|
|
.andExpect(status().isBadRequest())
|
|
.andExpect(jsonPath("$.code").value(ErrorCode.BAD_REQUEST.getCode()));
|
|
}
|
|
|
|
@Test
|
|
void statistics_shouldReturn200() throws Exception {
|
|
when(offerService.getStatistics(COMPANY_USER_ID, 6))
|
|
.thenReturn(Map.of("totalOffers", 10, "acceptanceRate", 0.6));
|
|
mockMvc.perform(get("/offers/statistics")
|
|
.header("Authorization", companyToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.code").value(200))
|
|
.andExpect(jsonPath("$.data.totalOffers").value(10));
|
|
}
|
|
|
|
@Test
|
|
void statistics_withMonths_shouldReturn200() throws Exception {
|
|
when(offerService.getStatistics(COMPANY_USER_ID, 12))
|
|
.thenReturn(Map.of("totalOffers", 5, "periodMonths", 12));
|
|
mockMvc.perform(get("/offers/statistics?months=12")
|
|
.header("Authorization", companyToken()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(jsonPath("$.data.periodMonths").value(12));
|
|
}
|
|
}
|
|
|