客户画像代码开发

This commit is contained in:
spllzh
2025-09-21 21:35:32 +08:00
parent f3eab70d43
commit c8a3ea254e
3 changed files with 1014 additions and 0 deletions

View File

@@ -0,0 +1,306 @@
package com.rj.controller;
import com.rj.controller.biz.CustomerProfileAnalysisController;
import com.rj.entity.CustomerProfileAnalysis;
import com.rj.service.biz.ICustomerProfileAnalysisService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDateTime;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
/**
* CustomerProfileAnalysisController 测试类
*
* @author 李中华
* @date 2025/1/15
*/
@WebMvcTest(CustomerProfileAnalysisController.class)
@DisplayName("客户画像分析控制器测试")
class CustomerProfileAnalysisControllerTest {
@Autowired
private MockMvc mockMvc;
@MockitoBean
private ICustomerProfileAnalysisService customerProfileAnalysisService;
private CustomerProfileAnalysis testAnalysis;
@BeforeEach
void setUp() {
testAnalysis = new CustomerProfileAnalysis();
testAnalysis.setId("test-id-123");
testAnalysis.setProfileAnalysisRecordId("profile-record-001");
testAnalysis.setAnalysisSceneType(1);
testAnalysis.setInteractionDate(LocalDateTime.now());
testAnalysis.setRelatedBusinessId("business-123");
testAnalysis.setDealerCode("DEALER001");
testAnalysis.setDealerName("测试经销商");
testAnalysis.setBigArea("华北区");
testAnalysis.setClientName("张三");
testAnalysis.setClientPhone("13800138000");
testAnalysis.setCreatedAt(LocalDateTime.now());
testAnalysis.setUpdatedAt(LocalDateTime.now());
testAnalysis.setRecordVersion(0);
testAnalysis.setIsDeleted(0);
}
@Test
@DisplayName("测试根据ID查询客户画像分析")
void testGetAnalysisById() throws Exception {
// Given
when(customerProfileAnalysisService.getById("test-id-123")).thenReturn(testAnalysis);
// When & Then
mockMvc.perform(get("/api/customer-profile-analysis/test-id-123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("查询成功"))
.andExpect(jsonPath("$.data.id").value("test-id-123"))
.andExpect(jsonPath("$.data.dealerName").value("测试经销商"));
verify(customerProfileAnalysisService, times(1)).getById("test-id-123");
}
@Test
@DisplayName("测试根据分析记录ID查询客户画像分析")
void testGetAnalysisByRecordId() throws Exception {
// Given
when(customerProfileAnalysisService.getByProfileAnalysisRecordId("profile-record-001"))
.thenReturn(testAnalysis);
// When & Then
mockMvc.perform(get("/api/customer-profile-analysis/by-record-id/profile-record-001"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("查询成功"))
.andExpect(jsonPath("$.data.profileAnalysisRecordId").value("profile-record-001"));
verify(customerProfileAnalysisService, times(1))
.getByProfileAnalysisRecordId("profile-record-001");
}
@Test
@DisplayName("测试根据业务ID查询客户画像分析")
void testGetAnalysisByBusinessId() throws Exception {
// Given
when(customerProfileAnalysisService.getByBusinessId("business-123"))
.thenReturn(testAnalysis);
// When & Then
mockMvc.perform(get("/api/customer-profile-analysis/by-business-id/business-123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("查询成功"))
.andExpect(jsonPath("$.data.relatedBusinessId").value("business-123"));
verify(customerProfileAnalysisService, times(1))
.getByBusinessId("business-123");
}
@Test
@DisplayName("测试新增客户画像分析")
void testAddAnalysis() throws Exception {
// Given
when(customerProfileAnalysisService.saveCustomerProfileAnalysis(any(CustomerProfileAnalysis.class)))
.thenReturn(true);
String requestJson = """
{
"profileAnalysisRecordId": "profile-record-002",
"analysisSceneType": 1,
"relatedBusinessId": "business-456",
"dealerCode": "DEALER002",
"dealerName": "测试经销商2",
"bigArea": "华东区",
"clientName": "李四",
"clientPhone": "13900139000"
}
""";
// When & Then
mockMvc.perform(post("/api/customer-profile-analysis/add")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("客户画像分析添加成功"));
verify(customerProfileAnalysisService, times(1))
.saveCustomerProfileAnalysis(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试修改客户画像分析")
void testUpdateAnalysis() throws Exception {
// Given
when(customerProfileAnalysisService.getById("test-id-123")).thenReturn(testAnalysis);
when(customerProfileAnalysisService.updateById(any(CustomerProfileAnalysis.class)))
.thenReturn(true);
String requestJson = """
{
"id": "test-id-123",
"profileAnalysisRecordId": "profile-record-001",
"analysisSceneType": 1,
"relatedBusinessId": "business-123",
"dealerCode": "DEALER001",
"dealerName": "测试经销商(修改)",
"bigArea": "华北区",
"clientName": "张三(修改)",
"clientPhone": "13800138000"
}
""";
// When & Then
mockMvc.perform(put("/api/customer-profile-analysis/update")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("客户画像分析修改成功"));
verify(customerProfileAnalysisService, times(1)).getById("test-id-123");
verify(customerProfileAnalysisService, times(1))
.updateById(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试删除客户画像分析")
void testDeleteAnalysis() throws Exception {
// Given
when(customerProfileAnalysisService.getById("test-id-123")).thenReturn(testAnalysis);
when(customerProfileAnalysisService.updateById(any(CustomerProfileAnalysis.class)))
.thenReturn(true);
// When & Then
mockMvc.perform(delete("/api/customer-profile-analysis/delete/test-id-123"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("客户画像分析删除成功"));
verify(customerProfileAnalysisService, times(1)).getById("test-id-123");
verify(customerProfileAnalysisService, times(1))
.updateById(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试批量删除客户画像分析")
void testBatchDeleteAnalysis() throws Exception {
// Given
when(customerProfileAnalysisService.getById(anyString())).thenReturn(testAnalysis);
when(customerProfileAnalysisService.updateById(any(CustomerProfileAnalysis.class)))
.thenReturn(true);
String requestJson = """
["test-id-123", "test-id-456"]
""";
// When & Then
mockMvc.perform(delete("/api/customer-profile-analysis/batch-delete")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.message").value("批量删除完成成功2失败0"));
verify(customerProfileAnalysisService, times(2)).getById(anyString());
verify(customerProfileAnalysisService, times(2))
.updateById(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试查询不存在的记录")
void testGetNonExistentAnalysis() throws Exception {
// Given
when(customerProfileAnalysisService.getById("non-existent-id")).thenReturn(null);
// When & Then
mockMvc.perform(get("/api/customer-profile-analysis/non-existent-id"))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value("客户画像分析不存在或已删除"));
verify(customerProfileAnalysisService, times(1)).getById("non-existent-id");
}
@Test
@DisplayName("测试新增客户画像分析失败")
void testAddAnalysisFailure() throws Exception {
// Given
when(customerProfileAnalysisService.saveCustomerProfileAnalysis(any(CustomerProfileAnalysis.class)))
.thenReturn(false);
String requestJson = """
{
"profileAnalysisRecordId": "profile-record-003",
"analysisSceneType": 1,
"relatedBusinessId": "business-789"
}
""";
// When & Then
mockMvc.perform(post("/api/customer-profile-analysis/add")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value("客户画像分析添加失败"));
verify(customerProfileAnalysisService, times(1))
.saveCustomerProfileAnalysis(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试修改客户画像分析 - ID为空")
void testUpdateAnalysisWithEmptyId() throws Exception {
// Given
String requestJson = """
{
"id": "",
"profileAnalysisRecordId": "profile-record-001",
"analysisSceneType": 1
}
""";
// When & Then
mockMvc.perform(put("/api/customer-profile-analysis/update")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value("ID不能为空"));
verify(customerProfileAnalysisService, never()).getById(anyString());
verify(customerProfileAnalysisService, never()).updateById(any(CustomerProfileAnalysis.class));
}
@Test
@DisplayName("测试批量删除客户画像分析 - 空ID列表")
void testBatchDeleteAnalysisWithEmptyList() throws Exception {
// Given
String requestJson = "[]";
// When & Then
mockMvc.perform(delete("/api/customer-profile-analysis/batch-delete")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.message").value("ID列表不能为空"));
verify(customerProfileAnalysisService, never()).getById(anyString());
verify(customerProfileAnalysisService, never()).updateById(any(CustomerProfileAnalysis.class));
}
}

View File

@@ -0,0 +1,183 @@
package com.rj.scheduler;
import com.rj.service.biz.ICpaBrandScoreStatisticsService;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.time.LocalDate;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
/**
* CpaBrandCoreScheduler 逻辑测试类
* 测试修改后的调度器逻辑
*
* @author 李中华
* @date 2025/1/15
*/
@SpringBootTest
@ActiveProfiles("test")
@DisplayName("经销商品牌得分统计调度器逻辑测试")
class CpaBrandCoreSchedulerLogicTest {
@Autowired
private ICpaBrandScoreStatisticsService cpaBrandScoreStatisticsService;
@Autowired
private CpaBrandCoreScheduler cpaBrandCoreScheduler;
@Test
@DisplayName("测试周统计任务 - 服务层自动计算时间范围")
void testGenerateWeeklyStatistics_AutoCalculateTimeRange() {
// Given
// When
cpaBrandCoreScheduler.generateWeeklyStatistics();
}
@Test
@DisplayName("测试月统计任务 - 服务层自动计算时间范围")
void testGenerateMonthlyStatistics_AutoCalculateTimeRange() {
// When
cpaBrandCoreScheduler.generateMonthlyStatistics();
}
@Test
@DisplayName("测试日统计任务 - 仍然需要传递具体日期")
void testGenerateDailyStatistics_StillRequiresDate() {
// When
cpaBrandCoreScheduler.generateDailyStatistics();
}
@Test
@DisplayName("测试总计统计任务 - 不需要日期参数")
void testGenerateTotalStatistics_NoDateRequired() {
// When
cpaBrandCoreScheduler.generateTotalStatistics();
}
@Test
@DisplayName("测试手动触发周统计 - 参数被忽略")
void testManualGenerateStatisticsByRange_Weekly_ParametersIgnored() {
// Given
LocalDate dummyStartDate = LocalDate.of(2025, 1, 1);
LocalDate dummyEndDate = LocalDate.of(2025, 1, 7);
int expectedCount = 20;
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("weekly"), eq(dummyStartDate), eq(dummyEndDate), eq("manual")))
.thenReturn(expectedCount);
// When
int actualCount = cpaBrandCoreScheduler.manualGenerateStatisticsByRange(dummyStartDate, dummyEndDate, "weekly");
// Then
assertEquals(expectedCount, actualCount);
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("weekly"), eq(dummyStartDate), eq(dummyEndDate), eq("manual"));
}
@Test
@DisplayName("测试手动触发月统计 - 参数被忽略")
void testManualGenerateStatisticsByRange_Monthly_ParametersIgnored() {
// Given
LocalDate dummyStartDate = LocalDate.of(2025, 1, 1);
LocalDate dummyEndDate = LocalDate.of(2025, 1, 31);
int expectedCount = 80;
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("monthly"), eq(dummyStartDate), eq(dummyEndDate), eq("manual")))
.thenReturn(expectedCount);
// When
int actualCount = cpaBrandCoreScheduler.manualGenerateStatisticsByRange(dummyStartDate, dummyEndDate, "monthly");
// Then
assertEquals(expectedCount, actualCount);
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("monthly"), eq(dummyStartDate), eq(dummyEndDate), eq("manual"));
}
@Test
@DisplayName("测试手动触发日统计 - 参数仍然有效")
void testManualGenerateStatisticsByRange_Daily_ParametersStillValid() {
// Given
LocalDate testDate = LocalDate.of(2025, 1, 15);
int expectedCount = 12;
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("daily"), eq(testDate), eq(testDate), eq("manual")))
.thenReturn(expectedCount);
// When
int actualCount = cpaBrandCoreScheduler.manualGenerateStatisticsByRange(testDate, testDate, "daily");
// Then
assertEquals(expectedCount, actualCount);
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("daily"), eq(testDate), eq(testDate), eq("manual"));
}
@Test
@DisplayName("测试手动触发总计统计 - 参数被忽略")
void testManualGenerateStatisticsByRange_Total_ParametersIgnored() {
// Given
LocalDate dummyStartDate = LocalDate.of(2025, 1, 1);
LocalDate dummyEndDate = LocalDate.of(2025, 12, 31);
int expectedCount = 500;
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("total"), eq(dummyStartDate), eq(dummyEndDate), eq("manual")))
.thenReturn(expectedCount);
// When
int actualCount = cpaBrandCoreScheduler.manualGenerateStatisticsByRange(dummyStartDate, dummyEndDate, "total");
// Then
assertEquals(expectedCount, actualCount);
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("total"), eq(dummyStartDate), eq(dummyEndDate), eq("manual"));
}
@Test
@DisplayName("测试异常处理 - 周统计任务异常")
void testGenerateWeeklyStatistics_Exception() {
// Given
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("weekly"), isNull(), isNull(), eq("system")))
.thenThrow(new RuntimeException("周统计服务异常"));
// When & Then
assertDoesNotThrow(() -> cpaBrandCoreScheduler.generateWeeklyStatistics());
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("weekly"), isNull(), isNull(), eq("system"));
}
@Test
@DisplayName("测试异常处理 - 月统计任务异常")
void testGenerateMonthlyStatistics_Exception() {
// Given
when(cpaBrandScoreStatisticsService.generateAndSaveStatistics(
eq("monthly"), isNull(), isNull(), eq("system")))
.thenThrow(new RuntimeException("月统计服务异常"));
// When & Then
assertDoesNotThrow(() -> cpaBrandCoreScheduler.generateMonthlyStatistics());
verify(cpaBrandScoreStatisticsService, times(1))
.generateAndSaveStatistics(eq("monthly"), isNull(), isNull(), eq("system"));
}
}