客户画像代码开发
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user