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.
 
 
 

225 lines
10 KiB

package com.mydreamjob.feedback;
import com.mydreamjob.application.Application;
import com.mydreamjob.application.ApplicationRepository;
import com.mydreamjob.common.exception.BusinessException;
import com.mydreamjob.common.exception.ErrorCode;
import com.mydreamjob.company.Company;
import com.mydreamjob.company.CompanyRepository;
import com.mydreamjob.feedback.dto.CandidateFeedbackRequest;
import com.mydreamjob.job.Job;
import com.mydreamjob.job.JobService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class CandidateFeedbackServiceTest {
@Mock private CandidateFeedbackRepository feedbackRepository;
@Mock private ApplicationRepository applicationRepository;
@Mock private JobService jobService;
@Mock private CompanyRepository companyRepository;
@InjectMocks private CandidateFeedbackService feedbackService;
private static final Long COMPANY_USER_ID = 10L; // 企业账号 userId
private static final Long COMPANY_ID = 20L; // 企业 id(job.companyId)
private static final Long OTHER_COMPANY_USER_ID = 11L; // 其他企业账号 userId
private static final Long OTHER_COMPANY_ID = 21L; // 其他企业 id
private static final Long ADMIN_LIKE_USER_ID = 1L; // 无归属企业、且恰等于某企业 id
private static final Long STUDENT_USER_ID = 100L;
private static final Long OTHER_STUDENT_ID = 101L;
private static final Long APPLICATION_ID = 1L;
private static final Long JOB_ID = 50L;
private Application app;
private Job job;
@BeforeEach
void setUp() {
app = Application.builder().id(APPLICATION_ID).jobId(JOB_ID).studentUserId(STUDENT_USER_ID).build();
job = Job.builder().id(JOB_ID).companyId(COMPANY_ID).title("Java").build();
}
private void mockCompanyOwnership(Long userId, Long companyId) {
when(companyRepository.findByOwnerUserId(userId))
.thenReturn(Optional.of(Company.builder().id(companyId).ownerUserId(userId).build()));
}
private CandidateFeedbackRequest buildReq() {
CandidateFeedbackRequest req = new CandidateFeedbackRequest();
req.setRating(4); req.setContent("Good candidate");
return req;
}
private void stubAppAndJob() {
when(applicationRepository.findById(APPLICATION_ID)).thenReturn(Optional.of(app));
when(jobService.getJob(JOB_ID)).thenReturn(job);
}
// ── 创建 ─────────────────────────────────────────────────
@Test void createFeedback_companyOwnsJob_shouldSucceed() {
stubAppAndJob();
mockCompanyOwnership(COMPANY_USER_ID, COMPANY_ID);
when(feedbackRepository.existsByApplicationId(APPLICATION_ID)).thenReturn(false);
when(feedbackRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
var r = feedbackService.createFeedback(COMPANY_USER_ID, APPLICATION_ID, buildReq());
assertEquals(4, r.getRating());
}
@Test void createFeedback_duplicate_shouldReturn409() {
stubAppAndJob();
mockCompanyOwnership(COMPANY_USER_ID, COMPANY_ID);
when(feedbackRepository.existsByApplicationId(APPLICATION_ID)).thenReturn(true);
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.createFeedback(COMPANY_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.DUPLICATE_FEEDBACK.getCode(), ex.getErrorCodeInt());
}
@Test void createFeedback_otherCompany_shouldReturn403() {
stubAppAndJob();
mockCompanyOwnership(OTHER_COMPANY_USER_ID, OTHER_COMPANY_ID);
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.createFeedback(OTHER_COMPANY_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void createFeedback_adminUserIdEqualsCompanyId_shouldReturn403() {
// userId 恰等于 job.companyId,但该用户无归属企业 -> 必须 403(安全回归)
Job adminJob = Job.builder().id(JOB_ID).companyId(ADMIN_LIKE_USER_ID).title("Java").build();
when(applicationRepository.findById(APPLICATION_ID)).thenReturn(Optional.of(app));
when(jobService.getJob(JOB_ID)).thenReturn(adminJob);
// 不 stub companyRepository:默认空 -> 无归属企业
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.createFeedback(ADMIN_LIKE_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void createFeedback_byStudent_shouldReturn403() {
stubAppAndJob();
// 学生无归属企业
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.createFeedback(STUDENT_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void createFeedback_appNotFound_shouldReturn404() {
when(applicationRepository.findById(999L)).thenReturn(Optional.empty());
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.createFeedback(COMPANY_USER_ID, 999L, buildReq()));
assertEquals(ErrorCode.APPLICATION_NOT_FOUND.getCode(), ex.getErrorCodeInt());
}
// ── 查询 ─────────────────────────────────────────────────
@Test void getFeedback_asCompany_shouldSucceed() {
stubAppAndJob();
mockCompanyOwnership(COMPANY_USER_ID, COMPANY_ID);
CandidateFeedback fb = CandidateFeedback.builder().applicationId(APPLICATION_ID).rating(4).content("Good").build();
when(feedbackRepository.findByApplicationId(APPLICATION_ID)).thenReturn(Optional.of(fb));
var r = feedbackService.getFeedback(COMPANY_USER_ID, APPLICATION_ID);
assertEquals(4, r.getRating());
}
@Test void getFeedback_asStudent_shouldSucceed() {
stubAppAndJob();
CandidateFeedback fb = CandidateFeedback.builder().applicationId(APPLICATION_ID).rating(4).content("Good").build();
when(feedbackRepository.findByApplicationId(APPLICATION_ID)).thenReturn(Optional.of(fb));
var r = feedbackService.getFeedback(STUDENT_USER_ID, APPLICATION_ID);
assertEquals(4, r.getRating());
}
@Test void getFeedback_adminUserIdEqualsCompanyId_shouldReturn403() {
Job adminJob = Job.builder().id(JOB_ID).companyId(ADMIN_LIKE_USER_ID).title("Java").build();
when(applicationRepository.findById(APPLICATION_ID)).thenReturn(Optional.of(app));
when(jobService.getJob(JOB_ID)).thenReturn(adminJob);
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.getFeedback(ADMIN_LIKE_USER_ID, APPLICATION_ID));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void getFeedback_otherStudent_shouldReturn403() {
stubAppAndJob();
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.getFeedback(OTHER_STUDENT_ID, APPLICATION_ID));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
// ── 修改 ─────────────────────────────────────────────────
@Test void updateFeedback_shouldSucceed() {
stubAppAndJob();
mockCompanyOwnership(COMPANY_USER_ID, COMPANY_ID);
CandidateFeedback fb = CandidateFeedback.builder().applicationId(APPLICATION_ID).rating(4).content("Good").build();
when(feedbackRepository.findByApplicationId(APPLICATION_ID)).thenReturn(Optional.of(fb));
when(feedbackRepository.save(any())).thenAnswer(inv -> inv.getArgument(0));
CandidateFeedbackRequest req = buildReq(); req.setRating(5);
var r = feedbackService.updateFeedback(COMPANY_USER_ID, APPLICATION_ID, req);
assertEquals(5, r.getRating());
}
@Test void updateFeedback_otherCompany_shouldReturn403() {
stubAppAndJob();
mockCompanyOwnership(OTHER_COMPANY_USER_ID, OTHER_COMPANY_ID);
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.updateFeedback(OTHER_COMPANY_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void updateFeedback_byStudent_shouldReturn403() {
stubAppAndJob();
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.updateFeedback(STUDENT_USER_ID, APPLICATION_ID, buildReq()));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
// ── 删除 ─────────────────────────────────────────────────
@Test void deleteFeedback_shouldSucceed() {
stubAppAndJob();
mockCompanyOwnership(COMPANY_USER_ID, COMPANY_ID);
CandidateFeedback fb = CandidateFeedback.builder().applicationId(APPLICATION_ID).build();
when(feedbackRepository.findByApplicationId(APPLICATION_ID)).thenReturn(Optional.of(fb));
assertDoesNotThrow(() -> feedbackService.deleteFeedback(COMPANY_USER_ID, APPLICATION_ID));
verify(feedbackRepository).delete(fb);
}
@Test void deleteFeedback_otherCompany_shouldReturn403() {
stubAppAndJob();
mockCompanyOwnership(OTHER_COMPANY_USER_ID, OTHER_COMPANY_ID);
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.deleteFeedback(OTHER_COMPANY_USER_ID, APPLICATION_ID));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
@Test void deleteFeedback_byStudent_shouldReturn403() {
stubAppAndJob();
BusinessException ex = assertThrows(BusinessException.class,
() -> feedbackService.deleteFeedback(STUDENT_USER_ID, APPLICATION_ID));
assertEquals(ErrorCode.FORBIDDEN.getCode(), ex.getErrorCodeInt());
}
}