6 changed files with 227 additions and 4 deletions
@ -0,0 +1,145 @@ |
|||||
|
package com.mydreamjob.application; |
||||
|
|
||||
|
import com.mydreamjob.auth.User; |
||||
|
import com.mydreamjob.company.Company; |
||||
|
import com.mydreamjob.job.Job; |
||||
|
import jakarta.persistence.EntityManager; |
||||
|
import jakarta.persistence.EntityManagerFactory; |
||||
|
import org.hibernate.SessionFactory; |
||||
|
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.redis.core.RedisTemplate; |
||||
|
import org.springframework.test.context.ActiveProfiles; |
||||
|
import org.springframework.test.web.servlet.MockMvc; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.util.Set; |
||||
|
import static org.junit.jupiter.api.Assertions.*; |
||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; |
||||
|
|
||||
|
@SpringBootTest(properties = "spring.jpa.properties.hibernate.generate_statistics=true") |
||||
|
@AutoConfigureMockMvc |
||||
|
@ActiveProfiles("integration-test") |
||||
|
@Transactional |
||||
|
class ApplicationSummaryIntegrationTest { |
||||
|
@Autowired EntityManager em; |
||||
|
@Autowired EntityManagerFactory emf; |
||||
|
@Autowired ApplicationService service; |
||||
|
@Autowired MockMvc mvc; |
||||
|
@Autowired com.mydreamjob.auth.AuthSessionService sessions; |
||||
|
@Autowired java.time.Clock clock; |
||||
|
@MockBean RedisTemplate<String, Object> redis; |
||||
|
long studentId; |
||||
|
long otherStudentId; |
||||
|
|
||||
|
@BeforeEach |
||||
|
void fixture() { |
||||
|
User student = user("summary-student", User.Role.STUDENT); |
||||
|
User other = user("summary-other", User.Role.STUDENT); |
||||
|
User owner = user("summary-company", User.Role.COMPANY); |
||||
|
studentId = student.getId(); |
||||
|
otherStudentId = other.getId(); |
||||
|
Company company = Company.builder().ownerUserId(owner.getId()).name("摘要测试企业").verified(true).build(); |
||||
|
em.persist(company); |
||||
|
for (int i = 0; i < 55; i++) { |
||||
|
Job job = Job.builder().companyId(company.getId()).title("岗位" + i).description("测试") |
||||
|
.city("上海").employmentType("FULL_TIME").status(i == 0 ? "CLOSED" : "PUBLISHED") |
||||
|
.salaryMin(i == 0 ? null : 10000).salaryMax(i == 0 ? null : 20000).build(); |
||||
|
em.persist(job); |
||||
|
em.persist(Application.builder().jobId(job.getId()).studentUserId(studentId) |
||||
|
.status(i % 2 == 0 ? "SUBMITTED" : "WITHDRAWN").build()); |
||||
|
if (i == 0) em.persist(Application.builder().jobId(job.getId()).studentUserId(otherStudentId) |
||||
|
.status("SUBMITTED").build()); |
||||
|
} |
||||
|
em.flush(); |
||||
|
em.clear(); |
||||
|
} |
||||
|
|
||||
|
private User user(String name, User.Role role) { |
||||
|
User user = User.builder().phone("139" + Math.abs(System.nanoTime() % 1_000_000_000L)) |
||||
|
.nickname(name).role(role).roles(Set.of(role)).active(true).verified(true).build(); |
||||
|
em.persist(user); |
||||
|
return user; |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void fixedQueryBudgetAndAllSummaryFieldsForOneTwentyAndFiftyRows() { |
||||
|
var stats = emf.unwrap(SessionFactory.class).getStatistics(); |
||||
|
for (int size : new int[]{1, 20, 50}) { |
||||
|
em.clear(); |
||||
|
stats.clear(); |
||||
|
var page = service.listStudentApplicationViews(studentId, null, 0, size); |
||||
|
long statements = stats.getPrepareStatementCount(); |
||||
|
assertEquals(3, statements, "当前页、总数、批量岗位摘要共三条 SQL,size=" + size); |
||||
|
assertEquals(55, page.getTotalElements()); |
||||
|
assertEquals(size, page.getNumberOfElements()); |
||||
|
for (var item : page) { |
||||
|
assertEquals(studentId, item.get("studentUserId")); |
||||
|
assertEquals("摘要测试企业", item.get("companyName")); |
||||
|
assertEquals("上海", item.get("city")); |
||||
|
assertEquals("FULL_TIME", item.get("employmentType")); |
||||
|
assertTrue(item.get("jobTitle").toString().startsWith("岗位")); |
||||
|
assertNotNull(item.get("companyId")); |
||||
|
assertTrue(item.containsKey("salaryMin")); |
||||
|
assertTrue(item.containsKey("salaryMax")); |
||||
|
assertNotNull(item.get("jobStatus")); |
||||
|
assertNotNull(item.get("status")); |
||||
|
assertNotNull(item.get("createdAt")); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void statusFilterPaginationAndIsolationArePreserved() { |
||||
|
var page = service.listStudentApplicationViews(studentId, "SUBMITTED", 1, 20); |
||||
|
assertEquals(28, page.getTotalElements()); |
||||
|
assertEquals(2, page.getTotalPages()); |
||||
|
assertEquals(1, page.getNumber()); |
||||
|
assertEquals(8, page.getNumberOfElements()); |
||||
|
page.forEach(item -> assertEquals("SUBMITTED", item.get("status"))); |
||||
|
var other = service.listStudentApplicationViews(otherStudentId, null, 0, 20); |
||||
|
assertEquals(1, other.getTotalElements()); |
||||
|
var closed = other.getContent().get(0); |
||||
|
assertEquals("CLOSED", closed.get("jobStatus")); |
||||
|
assertEquals("SUBMITTED", closed.get("status")); |
||||
|
assertNull(closed.get("salaryMin")); |
||||
|
assertNull(closed.get("salaryMax")); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void emptyPageSkipsSummarySql() { |
||||
|
var stats = emf.unwrap(SessionFactory.class).getStatistics(); |
||||
|
stats.clear(); |
||||
|
var page = service.listStudentApplicationViews(studentId, "HIRED", 0, 20); |
||||
|
assertTrue(page.isEmpty()); |
||||
|
assertEquals(0, page.getTotalElements()); |
||||
|
assertEquals(1, stats.getPrepareStatementCount()); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void rejectsInvalidPagination() { |
||||
|
assertThrows(com.mydreamjob.common.exception.BusinessException.class, |
||||
|
() -> service.listStudentApplicationViews(studentId, null, -1, 20)); |
||||
|
assertThrows(com.mydreamjob.common.exception.BusinessException.class, |
||||
|
() -> service.listStudentApplicationViews(studentId, null, 0, 101)); |
||||
|
} |
||||
|
|
||||
|
@Test |
||||
|
void httpListReturnsSummaryAndUnchangedPageEnvelope() throws Exception { |
||||
|
String bearer = "Bearer " + sessions.createSession(em.find(User.class, studentId), clock.instant(), |
||||
|
com.mydreamjob.audit.AuditContext.builder().requestId("application-summary-test").build()).accessToken(); |
||||
|
mvc.perform(get("/applications/me").header("Authorization", bearer).param("size", "20")) |
||||
|
.andExpect(status().isOk()).andExpect(jsonPath("$.code").value(200)) |
||||
|
.andExpect(jsonPath("$.data.total").value(55)) |
||||
|
.andExpect(jsonPath("$.data.totalPages").value(3)) |
||||
|
.andExpect(jsonPath("$.data.items.length()").value(20)) |
||||
|
.andExpect(jsonPath("$.data.items[0].companyName").value("摘要测试企业")) |
||||
|
.andExpect(jsonPath("$.data.items[0].jobTitle").isString()); |
||||
|
mvc.perform(get("/applications/me")).andExpect(status().isUnauthorized()); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue