fix: normalize comprehensive training scores

main
chenyuan 4 weeks ago
parent 3214e54b31
commit 85b4e83f7a

@ -0,0 +1,42 @@
# Task 2 report
## Status
Complete. Comprehensive training participates only when this teaching class has
both the publication marker and an enabled `comprehensive-case-training`
allocation. Reports expose `participating`; both reports and ranks normalize by
the sum of participating module weights.
## Commit
`18849c2a0e094c0cd48e9b87ce0f6e2e36fbf731` (`fix: normalize comprehensive training scores`).
## TDD evidence
- RED: `mvn '-Dtest=ScoreRankServiceImplTeachingClassTest,StudentExperimentReportServiceImplTest' test`
first failed at test compilation because `StudentExperimentReportModuleDTO`
lacked `getParticipating`; after adding the DTO contract it failed because the
report service had no class allocation mapper.
- GREEN: the same focused command passed: 5 tests, 0 failures, 0 errors.
- Full: `mvn test` passed: 209 tests, 0 failures, 0 errors, 0 skipped.
The Maven wrapper is incomplete in this worktree (`.mvn/wrapper` is absent),
so the commands above used the installed `mvn` executable.
## Changed files
- `src/test/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImplTeachingClassTest.java`
- `src/test/java/com/sztzjy/linkCommerce/service/impl/StudentExperimentReportServiceImplTest.java`
- `src/main/java/com/sztzjy/linkCommerce/entity/dto/StudentExperimentReportModuleDTO.java`
- `src/main/java/com/sztzjy/linkCommerce/service/impl/ScoreRankServiceImpl.java`
- `src/main/java/com/sztzjy/linkCommerce/service/impl/StudentExperimentReportServiceImpl.java`
## Self-check and concerns
- The retained weights are 10/30/10/10/20/20; no teacher configuration or
task visibility logic was changed.
- School/platform fallback allocations are used for normal task content, but
cannot activate the comprehensive module without a local class publication
record.
- There are no outstanding functional concerns. Maven emits pre-existing POM
warnings about project-local Aspose system dependencies.

@ -1,4 +1,4 @@
package com.sztzjy.linkCommerce.entity.dto; package com.sztzjy.linkCommerce.entity.dto;
import java.math.BigDecimal; import java.math.BigDecimal;
public class StudentExperimentReportModuleDTO { private String moduleName; private BigDecimal weight; private BigDecimal score=BigDecimal.ZERO; private Integer completedTaskCount=0; private Integer totalTaskCount=0; public class StudentExperimentReportModuleDTO { private String moduleName; private BigDecimal weight; private BigDecimal score=BigDecimal.ZERO; private Integer completedTaskCount=0; private Integer totalTaskCount=0; private Boolean participating=Boolean.FALSE;
public String getModuleName(){return moduleName;} public void setModuleName(String v){moduleName=v;} public BigDecimal getWeight(){return weight;} public void setWeight(BigDecimal v){weight=v;} public BigDecimal getScore(){return score;} public void setScore(BigDecimal v){score=v;} public Integer getCompletedTaskCount(){return completedTaskCount;} public void setCompletedTaskCount(Integer v){completedTaskCount=v;} public Integer getTotalTaskCount(){return totalTaskCount;} public void setTotalTaskCount(Integer v){totalTaskCount=v;} } public String getModuleName(){return moduleName;} public void setModuleName(String v){moduleName=v;} public BigDecimal getWeight(){return weight;} public void setWeight(BigDecimal v){weight=v;} public BigDecimal getScore(){return score;} public void setScore(BigDecimal v){score=v;} public Integer getCompletedTaskCount(){return completedTaskCount;} public void setCompletedTaskCount(Integer v){completedTaskCount=v;} public Integer getTotalTaskCount(){return totalTaskCount;} public void setTotalTaskCount(Integer v){totalTaskCount=v;} public Boolean getParticipating(){return participating;} public void setParticipating(Boolean v){participating=v;} }

@ -343,13 +343,16 @@ public class ScoreRankServiceImpl implements ScoreRankService {
} }
TaskAllocationExample allocationExample = new TaskAllocationExample(); TaskAllocationExample allocationExample = new TaskAllocationExample();
allocationExample.createCriteria().andClassIdEqualTo(teachingClassId); allocationExample.createCriteria().andClassIdEqualTo(teachingClassId);
List<TaskAllocation> classAllocations = taskAllocationMapper.selectByExample(allocationExample);
boolean comprehensiveParticipating = hasPublishedComprehensiveTask(classAllocations);
List<TaskAllocation> allocations = schoolDefaultTaskService == null List<TaskAllocation> allocations = schoolDefaultTaskService == null
? taskAllocationMapper.selectByExample(allocationExample) ? classAllocations
: schoolDefaultTaskService.resolveForTeachingClass(teachingClassId); : schoolDefaultTaskService.resolveForTeachingClass(teachingClassId);
Map<String, List<Integer>> scoresByProject = new HashMap<>(); Map<String, List<Integer>> scoresByProject = new HashMap<>();
for (TaskAllocation allocation : allocations == null ? Collections.<TaskAllocation>emptyList() : allocations) { for (TaskAllocation allocation : allocations == null ? Collections.<TaskAllocation>emptyList() : allocations) {
if (allocation.getDisabledStatus() != null && allocation.getDisabledStatus() == 1 if (allocation.getDisabledStatus() != null && allocation.getDisabledStatus() == 1
|| TaskAllocation.PUBLICATION_MARKER.equals(allocation.getModule())) { || TaskAllocation.PUBLICATION_MARKER.equals(allocation.getModule())
|| ("comprehensive-case-training".equals(allocation.getModule()) && !comprehensiveParticipating)) {
continue; continue;
} }
TrainingTask task = trainingTaskMapper.selectByTaskKey(allocation.getModule()); TrainingTask task = trainingTaskMapper.selectByTaskKey(allocation.getModule());
@ -366,7 +369,40 @@ public class ScoreRankServiceImpl implements ScoreRankService {
.add(projectAverage(scoresByProject, "产品开发与测试验证").multiply(weight.getDevelopmentValidationWeight())) .add(projectAverage(scoresByProject, "产品开发与测试验证").multiply(weight.getDevelopmentValidationWeight()))
.add(projectAverage(scoresByProject, "产品上线与运营推广").multiply(weight.getLaunchOperationWeight())) .add(projectAverage(scoresByProject, "产品上线与运营推广").multiply(weight.getLaunchOperationWeight()))
.add(projectAverage(scoresByProject, "综合实训").multiply(weight.getComprehensiveTrainingWeight())) .add(projectAverage(scoresByProject, "综合实训").multiply(weight.getComprehensiveTrainingWeight()))
.setScale(2, BigDecimal.ROUND_HALF_UP); .divide(participatingWeight(weight, comprehensiveParticipating), 2, BigDecimal.ROUND_HALF_UP);
}
private boolean hasPublishedComprehensiveTask(List<TaskAllocation> allocations) {
boolean published = false;
boolean enabled = false;
for (TaskAllocation allocation : allocations == null ? Collections.<TaskAllocation>emptyList() : allocations) {
if (allocation == null) {
continue;
}
if (TaskAllocation.PUBLICATION_MARKER.equals(allocation.getModule())) {
published = true;
} else if ("comprehensive-case-training".equals(allocation.getModule())
&& (allocation.getDisabledStatus() == null || allocation.getDisabledStatus() == 0)) {
enabled = true;
}
}
return published && enabled;
}
private BigDecimal participatingWeight(TeachingClassScoreWeight weight, boolean comprehensiveParticipating) {
BigDecimal total = safeWeight(weight.getFoundationWeight())
.add(safeWeight(weight.getMarketInsightWeight()))
.add(safeWeight(weight.getPlanningDesignWeight()))
.add(safeWeight(weight.getDevelopmentValidationWeight()))
.add(safeWeight(weight.getLaunchOperationWeight()));
if (comprehensiveParticipating) {
total = total.add(safeWeight(weight.getComprehensiveTrainingWeight()));
}
return total.signum() == 0 ? BigDecimal.ONE : total;
}
private BigDecimal safeWeight(BigDecimal weight) {
return weight == null ? BigDecimal.ZERO : weight;
} }
private BigDecimal projectAverage(Map<String, List<Integer>> scoresByProject, String project) { private BigDecimal projectAverage(Map<String, List<Integer>> scoresByProject, String project) {

@ -2,9 +2,10 @@ package com.sztzjy.linkCommerce.service.impl;
import com.sztzjy.linkCommerce.config.security.JwtUser; import com.sztzjy.linkCommerce.entity.*; import com.sztzjy.linkCommerce.entity.dto.*; import com.sztzjy.linkCommerce.mapper.*; import com.sztzjy.linkCommerce.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.sztzjy.linkCommerce.config.security.JwtUser; import com.sztzjy.linkCommerce.entity.*; import com.sztzjy.linkCommerce.entity.dto.*; import com.sztzjy.linkCommerce.mapper.*; import com.sztzjy.linkCommerce.service.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
import java.math.*; import java.util.*; import java.math.*; import java.util.*;
@Service public class StudentExperimentReportServiceImpl implements StudentExperimentReportService { @Service public class StudentExperimentReportServiceImpl implements StudentExperimentReportService {
@Autowired public StudentTeachingClassResolver studentTeachingClassResolver; @Autowired public SchoolDefaultTaskService schoolDefaultTaskService; @Autowired public TrainingTaskMapper trainingTaskMapper; @Autowired public StudentTrainingAnswerMapper studentTrainingAnswerMapper; @Autowired(required=false) public TeachingClassScoreWeightMapper teachingClassScoreWeightMapper; @Autowired public StudentTeachingClassResolver studentTeachingClassResolver; @Autowired public SchoolDefaultTaskService schoolDefaultTaskService; @Autowired public TrainingTaskMapper trainingTaskMapper; @Autowired public StudentTrainingAnswerMapper studentTrainingAnswerMapper; @Autowired(required=false) public TeachingClassScoreWeightMapper teachingClassScoreWeightMapper; @Autowired(required=false) public TaskAllocationMapper taskAllocationMapper;
private static final String[] NAMES={"互联网产品开发基础认知","市场洞察与需求分析","产品规划与设计","产品开发与测试验证","产品上线与运营推广","综合实训"}; private static final String[] NAMES={"互联网产品开发基础认知","市场洞察与需求分析","产品规划与设计","产品开发与测试验证","产品上线与运营推广","综合实训"};
private static final BigDecimal[] DEFAULTS={new BigDecimal("0.10"),new BigDecimal("0.30"),new BigDecimal("0.10"),new BigDecimal("0.10"),new BigDecimal("0.20"),new BigDecimal("0.20")}; private static final BigDecimal[] DEFAULTS={new BigDecimal("0.10"),new BigDecimal("0.30"),new BigDecimal("0.10"),new BigDecimal("0.10"),new BigDecimal("0.20"),new BigDecimal("0.20")};
public StudentExperimentReportDTO getCurrentReport(JwtUser user){ String classId=studentTeachingClassResolver.resolveRequired(user); StudentExperimentReportDTO report=new StudentExperimentReportDTO(); report.setTeachingClassId(classId); List<StudentExperimentReportModuleDTO> modules=new ArrayList<>(); Map<String,StudentExperimentReportModuleDTO> index=new HashMap<>(); BigDecimal[] weights=weights(classId); for(int i=0;i<NAMES.length;i++){StudentExperimentReportModuleDTO m=new StudentExperimentReportModuleDTO();m.setModuleName(NAMES[i]);m.setWeight(weights[i]);modules.add(m);index.put(NAMES[i],m);} List<StudentExperimentReportTaskDTO> tasks=new ArrayList<>(); for(TaskAllocation a: schoolDefaultTaskService.resolveForTeachingClass(classId)){if(a==null||a.getDisabledStatus()!=null&&a.getDisabledStatus()==1||TaskAllocation.PUBLICATION_MARKER.equals(a.getModule()))continue; TrainingTask t=trainingTaskMapper.selectByTaskKey(a.getModule()); if(t==null||!index.containsKey(t.getProjectName()))continue; StudentTrainingAnswer ans=studentTrainingAnswerMapper.selectByStudentClassAndTask(user.getUserId(),classId,t.getId()); StudentExperimentReportModuleDTO m=index.get(t.getProjectName());m.setTotalTaskCount(m.getTotalTaskCount()+1);int score=ans==null||ans.getAiAssessmentScore()==null?0:ans.getAiAssessmentScore();m.setScore(m.getScore().add(BigDecimal.valueOf(score)));if(ans!=null&&(Boolean.TRUE.equals(ans.getSubmitted())||"COMPLETED".equals(ans.getProgressStatus())))m.setCompletedTaskCount(m.getCompletedTaskCount()+1);StudentExperimentReportTaskDTO row=new StudentExperimentReportTaskDTO();row.setTaskName(t.getTaskName());row.setModuleName(t.getProjectName());if(ans!=null){row.setProgressStatus(ans.getProgressStatus());row.setSubmitted(ans.getSubmitted());row.setAiAssessmentScore(ans.getAiAssessmentScore());}tasks.add(row);} BigDecimal total=BigDecimal.ZERO;for(StudentExperimentReportModuleDTO m:modules){BigDecimal score=m.getTotalTaskCount()==0?BigDecimal.ZERO:m.getScore().divide(BigDecimal.valueOf(m.getTotalTaskCount()),2,BigDecimal.ROUND_HALF_UP);m.setScore(score);total=total.add(score.multiply(m.getWeight()));}report.setTotalScore(total.setScale(2,BigDecimal.ROUND_HALF_UP));report.setModules(modules);report.setTasks(tasks);return report; } public StudentExperimentReportDTO getCurrentReport(JwtUser user){ String classId=studentTeachingClassResolver.resolveRequired(user); StudentExperimentReportDTO report=new StudentExperimentReportDTO(); report.setTeachingClassId(classId); List<StudentExperimentReportModuleDTO> modules=new ArrayList<>(); Map<String,StudentExperimentReportModuleDTO> index=new HashMap<>(); BigDecimal[] weights=weights(classId); boolean comprehensiveParticipating=hasPublishedComprehensiveTask(classId); for(int i=0;i<NAMES.length;i++){StudentExperimentReportModuleDTO m=new StudentExperimentReportModuleDTO();m.setModuleName(NAMES[i]);m.setWeight(weights[i]);m.setParticipating(i<NAMES.length-1||comprehensiveParticipating);modules.add(m);index.put(NAMES[i],m);} List<StudentExperimentReportTaskDTO> tasks=new ArrayList<>(); for(TaskAllocation a: schoolDefaultTaskService.resolveForTeachingClass(classId)){if(a==null||a.getDisabledStatus()!=null&&a.getDisabledStatus()==1||TaskAllocation.PUBLICATION_MARKER.equals(a.getModule())||("comprehensive-case-training".equals(a.getModule())&&!comprehensiveParticipating))continue; TrainingTask t=trainingTaskMapper.selectByTaskKey(a.getModule()); if(t==null||!index.containsKey(t.getProjectName()))continue; StudentTrainingAnswer ans=studentTrainingAnswerMapper.selectByStudentClassAndTask(user.getUserId(),classId,t.getId()); StudentExperimentReportModuleDTO m=index.get(t.getProjectName());m.setTotalTaskCount(m.getTotalTaskCount()+1);int score=ans==null||ans.getAiAssessmentScore()==null?0:ans.getAiAssessmentScore();m.setScore(m.getScore().add(BigDecimal.valueOf(score)));if(ans!=null&&(Boolean.TRUE.equals(ans.getSubmitted())||"COMPLETED".equals(ans.getProgressStatus())))m.setCompletedTaskCount(m.getCompletedTaskCount()+1);StudentExperimentReportTaskDTO row=new StudentExperimentReportTaskDTO();row.setTaskName(t.getTaskName());row.setModuleName(t.getProjectName());if(ans!=null){row.setProgressStatus(ans.getProgressStatus());row.setSubmitted(ans.getSubmitted());row.setAiAssessmentScore(ans.getAiAssessmentScore());}tasks.add(row);} BigDecimal total=BigDecimal.ZERO;BigDecimal participatingWeight=BigDecimal.ZERO;for(StudentExperimentReportModuleDTO m:modules){BigDecimal score=m.getTotalTaskCount()==0?BigDecimal.ZERO:m.getScore().divide(BigDecimal.valueOf(m.getTotalTaskCount()),2,BigDecimal.ROUND_HALF_UP);m.setScore(score);if(Boolean.TRUE.equals(m.getParticipating())){BigDecimal weight=m.getWeight()==null?BigDecimal.ZERO:m.getWeight();total=total.add(score.multiply(weight));participatingWeight=participatingWeight.add(weight);}}report.setTotalScore(participatingWeight.signum()==0?BigDecimal.ZERO:total.divide(participatingWeight,2,BigDecimal.ROUND_HALF_UP));report.setModules(modules);report.setTasks(tasks);return report; }
private boolean hasPublishedComprehensiveTask(String classId){if(taskAllocationMapper==null)return false;TaskAllocationExample example=new TaskAllocationExample();example.createCriteria().andClassIdEqualTo(classId);List<TaskAllocation> allocations=taskAllocationMapper.selectByExample(example);boolean published=false;boolean enabled=false;for(TaskAllocation allocation:allocations==null?Collections.<TaskAllocation>emptyList():allocations){if(allocation==null)continue;if(TaskAllocation.PUBLICATION_MARKER.equals(allocation.getModule()))published=true;else if("comprehensive-case-training".equals(allocation.getModule())&&(allocation.getDisabledStatus()==null||allocation.getDisabledStatus()==0))enabled=true;}return published&&enabled;}
private BigDecimal[] weights(String id){TeachingClassScoreWeight w=teachingClassScoreWeightMapper==null?null:teachingClassScoreWeightMapper.selectByTeachingClassId(id);if(w==null)return DEFAULTS;return new BigDecimal[]{w.getFoundationWeight(),w.getMarketInsightWeight(),w.getPlanningDesignWeight(),w.getDevelopmentValidationWeight(),w.getLaunchOperationWeight(),w.getComprehensiveTrainingWeight()};} private BigDecimal[] weights(String id){TeachingClassScoreWeight w=teachingClassScoreWeightMapper==null?null:teachingClassScoreWeightMapper.selectByTeachingClassId(id);if(w==null)return DEFAULTS;return new BigDecimal[]{w.getFoundationWeight(),w.getMarketInsightWeight(),w.getPlanningDesignWeight(),w.getDevelopmentValidationWeight(),w.getLaunchOperationWeight(),w.getComprehensiveTrainingWeight()};}
} }

@ -4,8 +4,17 @@ import com.sztzjy.linkCommerce.entity.SchoolClass;
import com.sztzjy.linkCommerce.entity.StuRank; import com.sztzjy.linkCommerce.entity.StuRank;
import com.sztzjy.linkCommerce.entity.StuRankExample; import com.sztzjy.linkCommerce.entity.StuRankExample;
import com.sztzjy.linkCommerce.entity.TeachingClassStudent; import com.sztzjy.linkCommerce.entity.TeachingClassStudent;
import com.sztzjy.linkCommerce.entity.TaskAllocation;
import com.sztzjy.linkCommerce.entity.StudentTrainingAnswer;
import com.sztzjy.linkCommerce.entity.TeachingClassScoreWeight;
import com.sztzjy.linkCommerce.entity.TrainingTask;
import com.sztzjy.linkCommerce.entity.Userinfo; import com.sztzjy.linkCommerce.entity.Userinfo;
import com.sztzjy.linkCommerce.entity.Weight; import com.sztzjy.linkCommerce.entity.Weight;
import com.sztzjy.linkCommerce.entity.dto.StudentExperimentReportModuleDTO;
import com.sztzjy.linkCommerce.mapper.StudentTrainingAnswerMapper;
import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassScoreWeightMapper;
import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper;
import com.sztzjy.linkCommerce.mapper.SchoolClassMapper; import com.sztzjy.linkCommerce.mapper.SchoolClassMapper;
import com.sztzjy.linkCommerce.mapper.StuCountMapper; import com.sztzjy.linkCommerce.mapper.StuCountMapper;
import com.sztzjy.linkCommerce.mapper.StuGradeMapper; import com.sztzjy.linkCommerce.mapper.StuGradeMapper;
@ -14,6 +23,7 @@ import com.sztzjy.linkCommerce.mapper.StuStudyTimeMapper;
import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper; import com.sztzjy.linkCommerce.mapper.TeachingClassStudentMapper;
import com.sztzjy.linkCommerce.mapper.UserinfoMapper; import com.sztzjy.linkCommerce.mapper.UserinfoMapper;
import com.sztzjy.linkCommerce.mapper.WeightMapper; import com.sztzjy.linkCommerce.mapper.WeightMapper;
import com.sztzjy.linkCommerce.service.SchoolDefaultTaskService;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -65,6 +75,36 @@ class ScoreRankServiceImplTeachingClassTest {
assertEquals("student-2", rankCaptor.getAllValues().get(1).getUserId()); assertEquals("student-2", rankCaptor.getAllValues().get(1).getUserId());
} }
@Test
void doRankTeachingClassNormalizesFiveModulesWhenComprehensiveIsNotPublishedByClass() {
ScoreRankServiceImpl service = serviceWithMocks();
SchoolClass teachingClass = new SchoolClass();
teachingClass.setSchoolClassId("teaching-1");
teachingClass.setClassName("teaching one");
teachingClass.setClassType("TEACHING");
when(service.schoolClassMapper.selectByPrimaryKey("teaching-1")).thenReturn(teachingClass);
when(service.teachingClassStudentMapper.selectByTeachingClassId("teaching-1")).thenReturn(Collections.singletonList(member("student-1")));
when(service.userinfoMapper.selectByPrimaryKey("student-1")).thenReturn(student("student-1", "s001"));
when(service.weightMapper.selectByPrimaryKey("school-1")).thenReturn(weight());
when(service.taskAllocationMapper.selectByExample(any())).thenReturn(Collections.emptyList());
when(service.schoolDefaultTaskService.resolveForTeachingClass("teaching-1")).thenReturn(allocations(6));
String[] names = (String[]) org.springframework.test.util.ReflectionTestUtils.getField(StudentExperimentReportServiceImpl.class, "NAMES");
for (int i = 0; i < 6; i++) {
when(service.trainingTaskMapper.selectByTaskKey(taskKey(i))).thenReturn(trainingTask("id-" + i, names[i]));
if (i < 5) {
when(service.studentTrainingAnswerMapper.selectByStudentClassAndTask("student-1", "teaching-1", "id-" + i)).thenReturn(answer(100));
}
}
when(service.teachingClassScoreWeightMapper.selectByTeachingClassId("teaching-1")).thenReturn(sixWeights());
assertTrue(service.doRankTeachingClass("school-1", "teaching-1"));
ArgumentCaptor<StuRank> rankCaptor = ArgumentCaptor.forClass(StuRank.class);
verify(service.stuRankMapper).insert(rankCaptor.capture());
assertEquals(new BigDecimal("100.00"), rankCaptor.getValue().getScore());
}
private ScoreRankServiceImpl serviceWithMocks() { private ScoreRankServiceImpl serviceWithMocks() {
ScoreRankServiceImpl service = new ScoreRankServiceImpl(); ScoreRankServiceImpl service = new ScoreRankServiceImpl();
service.stuRankMapper = mock(StuRankMapper.class); service.stuRankMapper = mock(StuRankMapper.class);
@ -75,6 +115,11 @@ class ScoreRankServiceImplTeachingClassTest {
service.stuStudyTimeMapper = mock(StuStudyTimeMapper.class); service.stuStudyTimeMapper = mock(StuStudyTimeMapper.class);
service.schoolClassMapper = mock(SchoolClassMapper.class); service.schoolClassMapper = mock(SchoolClassMapper.class);
service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class); service.teachingClassStudentMapper = mock(TeachingClassStudentMapper.class);
service.taskAllocationMapper = mock(TaskAllocationMapper.class);
service.trainingTaskMapper = mock(TrainingTaskMapper.class);
service.studentTrainingAnswerMapper = mock(StudentTrainingAnswerMapper.class);
service.teachingClassScoreWeightMapper = mock(TeachingClassScoreWeightMapper.class);
service.schoolDefaultTaskService = mock(SchoolDefaultTaskService.class);
return service; return service;
} }
@ -106,6 +151,45 @@ class ScoreRankServiceImplTeachingClassTest {
return weight; return weight;
} }
private java.util.List<TaskAllocation> allocations(int count) {
TaskAllocation[] values = new TaskAllocation[count];
for (int i = 0; i < count; i++) {
TaskAllocation allocation = new TaskAllocation();
allocation.setModule(taskKey(i));
allocation.setDisabledStatus((byte) 0);
values[i] = allocation;
}
return Arrays.asList(values);
}
private TrainingTask trainingTask(String id, String project) {
TrainingTask task = new TrainingTask();
task.setId(id);
task.setProjectName(project);
return task;
}
private StudentTrainingAnswer answer(int score) {
StudentTrainingAnswer answer = new StudentTrainingAnswer();
answer.setAiAssessmentScore(score);
return answer;
}
private String taskKey(int index) {
return index == 5 ? "comprehensive-case-training" : "task-" + index;
}
private TeachingClassScoreWeight sixWeights() {
TeachingClassScoreWeight weight = new TeachingClassScoreWeight();
weight.setFoundationWeight(new BigDecimal("0.10"));
weight.setMarketInsightWeight(new BigDecimal("0.30"));
weight.setPlanningDesignWeight(new BigDecimal("0.10"));
weight.setDevelopmentValidationWeight(new BigDecimal("0.10"));
weight.setLaunchOperationWeight(new BigDecimal("0.20"));
weight.setComprehensiveTrainingWeight(new BigDecimal("0.20"));
return weight;
}
private void assertCriterion(StuRankExample example, String condition, Object value) { private void assertCriterion(StuRankExample example, String condition, Object value) {
assertTrue(example.getOredCriteria().get(0).getAllCriteria().stream() assertTrue(example.getOredCriteria().get(0).getAllCriteria().stream()
.anyMatch(criterion -> condition.equals(criterion.getCondition()) && value.equals(criterion.getValue()))); .anyMatch(criterion -> condition.equals(criterion.getCondition()) && value.equals(criterion.getValue())));

@ -6,6 +6,7 @@ import com.sztzjy.linkCommerce.entity.TaskAllocation;
import com.sztzjy.linkCommerce.entity.TrainingTask; import com.sztzjy.linkCommerce.entity.TrainingTask;
import com.sztzjy.linkCommerce.entity.dto.StudentExperimentReportDTO; import com.sztzjy.linkCommerce.entity.dto.StudentExperimentReportDTO;
import com.sztzjy.linkCommerce.mapper.StudentTrainingAnswerMapper; import com.sztzjy.linkCommerce.mapper.StudentTrainingAnswerMapper;
import com.sztzjy.linkCommerce.mapper.TaskAllocationMapper;
import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper; import com.sztzjy.linkCommerce.mapper.TrainingTaskMapper;
import com.sztzjy.linkCommerce.service.SchoolDefaultTaskService; import com.sztzjy.linkCommerce.service.SchoolDefaultTaskService;
import com.sztzjy.linkCommerce.service.StudentTeachingClassResolver; import com.sztzjy.linkCommerce.service.StudentTeachingClassResolver;
@ -14,6 +15,8 @@ import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ -40,12 +43,81 @@ class StudentExperimentReportServiceImplTest {
assertEquals(6, report.getModules().size()); assertEquals(6, report.getModules().size());
assertEquals(new BigDecimal("80.00"), report.getModules().get(1).getScore()); assertEquals(new BigDecimal("80.00"), report.getModules().get(1).getScore());
assertEquals(new BigDecimal("0.30"), report.getModules().get(1).getWeight()); assertEquals(new BigDecimal("0.30"), report.getModules().get(1).getWeight());
assertEquals(new BigDecimal("24.00"), report.getTotalScore()); assertEquals(new BigDecimal("30.00"), report.getTotalScore());
assertEquals(1, report.getTasks().size()); assertEquals(1, report.getTasks().size());
} }
@Test
void normalizesFiveModulesWhenComprehensiveIsOnlyInTheSchoolDefault() {
StudentExperimentReportServiceImpl service = new StudentExperimentReportServiceImpl();
StudentTeachingClassResolver resolver = mock(StudentTeachingClassResolver.class);
SchoolDefaultTaskService taskService = mock(SchoolDefaultTaskService.class);
TrainingTaskMapper taskMapper = mock(TrainingTaskMapper.class);
StudentTrainingAnswerMapper answerMapper = mock(StudentTrainingAnswerMapper.class);
TaskAllocationMapper allocationMapper = mock(TaskAllocationMapper.class);
ReflectionTestUtils.setField(service, "studentTeachingClassResolver", resolver);
ReflectionTestUtils.setField(service, "schoolDefaultTaskService", taskService);
ReflectionTestUtils.setField(service, "trainingTaskMapper", taskMapper);
ReflectionTestUtils.setField(service, "studentTrainingAnswerMapper", answerMapper);
ReflectionTestUtils.setField(service, "taskAllocationMapper", allocationMapper);
when(resolver.resolveRequired(any())).thenReturn("class-1");
when(allocationMapper.selectByExample(any())).thenReturn(Collections.emptyList());
List<String> names = moduleNames();
when(taskService.resolveForTeachingClass("class-1")).thenReturn(allocations(6));
for (int i = 0; i < 6; i++) {
when(taskMapper.selectByTaskKey(taskKey(i))).thenReturn(task("id-" + i, names.get(i), taskKey(i)));
}
when(answerMapper.selectByStudentClassAndTask(eq("student-1"), eq("class-1"), anyString()))
.thenReturn(answer(100, true));
StudentExperimentReportDTO report = service.getCurrentReport(student());
assertEquals(new BigDecimal("100.00"), report.getTotalScore());
assertEquals(Boolean.FALSE, report.getModules().get(5).getParticipating());
assertEquals(0, report.getModules().get(5).getTotalTaskCount());
}
@Test
void publishedComprehensiveParticipatesAtZeroWhenStudentHasNotAnswered() {
StudentExperimentReportServiceImpl service = new StudentExperimentReportServiceImpl();
StudentTeachingClassResolver resolver = mock(StudentTeachingClassResolver.class);
SchoolDefaultTaskService taskService = mock(SchoolDefaultTaskService.class);
TrainingTaskMapper taskMapper = mock(TrainingTaskMapper.class);
StudentTrainingAnswerMapper answerMapper = mock(StudentTrainingAnswerMapper.class);
TaskAllocationMapper allocationMapper = mock(TaskAllocationMapper.class);
ReflectionTestUtils.setField(service, "studentTeachingClassResolver", resolver);
ReflectionTestUtils.setField(service, "schoolDefaultTaskService", taskService);
ReflectionTestUtils.setField(service, "trainingTaskMapper", taskMapper);
ReflectionTestUtils.setField(service, "studentTrainingAnswerMapper", answerMapper);
ReflectionTestUtils.setField(service, "taskAllocationMapper", allocationMapper);
when(resolver.resolveRequired(any())).thenReturn("class-1");
when(allocationMapper.selectByExample(any())).thenReturn(Arrays.asList(marker(), allocation(taskKey(5))));
List<String> names = moduleNames();
when(taskService.resolveForTeachingClass("class-1")).thenReturn(allocations(6));
for (int i = 0; i < 6; i++) {
when(taskMapper.selectByTaskKey(taskKey(i))).thenReturn(task("id-" + i, names.get(i), taskKey(i)));
}
for (int i = 0; i < 5; i++) {
when(answerMapper.selectByStudentClassAndTask("student-1", "class-1", "id-" + i)).thenReturn(answer(100, true));
}
StudentExperimentReportDTO report = service.getCurrentReport(student());
assertEquals(new BigDecimal("80.00"), report.getTotalScore());
assertEquals(Boolean.TRUE, report.getModules().get(5).getParticipating());
assertEquals(1, report.getModules().get(5).getTotalTaskCount());
assertEquals(BigDecimal.ZERO.setScale(2), report.getModules().get(5).getScore());
}
private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("student-1"); user.setRoleId(4); return user; } private JwtUser student() { JwtUser user = new JwtUser(); user.setUserId("student-1"); user.setRoleId(4); return user; }
private TaskAllocation allocation(String key) { return allocation(key, (byte) 0); } private TaskAllocation allocation(String key) { return allocation(key, (byte) 0); }
private TaskAllocation allocation(String key, byte disabled) { TaskAllocation value = new TaskAllocation(); value.setModule(key); value.setDisabledStatus(disabled); return value; } private TaskAllocation allocation(String key, byte disabled) { TaskAllocation value = new TaskAllocation(); value.setModule(key); value.setDisabledStatus(disabled); return value; }
private TrainingTask task(String id, String project, String name) { TrainingTask value = new TrainingTask(); value.setId(id); value.setProjectName(project); value.setTaskName(name); return value; } private TrainingTask task(String id, String project, String name) { TrainingTask value = new TrainingTask(); value.setId(id); value.setProjectName(project); value.setTaskName(name); return value; }
private StudentTrainingAnswer answer(int score, boolean submitted) { StudentTrainingAnswer value = new StudentTrainingAnswer(); value.setAiAssessmentScore(score); value.setSubmitted(submitted); value.setProgressStatus("COMPLETED"); return value; } private StudentTrainingAnswer answer(int score, boolean submitted) { StudentTrainingAnswer value = new StudentTrainingAnswer(); value.setAiAssessmentScore(score); value.setSubmitted(submitted); value.setProgressStatus("COMPLETED"); return value; }
private TaskAllocation marker() { return allocation(TaskAllocation.PUBLICATION_MARKER, (byte) 1); }
private List<TaskAllocation> allocations(int count) { TaskAllocation[] values = new TaskAllocation[count]; for (int i = 0; i < count; i++) values[i] = allocation(taskKey(i)); return Arrays.asList(values); }
private String taskKey(int index) { return index == 5 ? "comprehensive-case-training" : "task-" + index; }
private List<String> moduleNames() { return Arrays.asList((String[]) ReflectionTestUtils.getField(StudentExperimentReportServiceImpl.class, "NAMES")); }
} }

Loading…
Cancel
Save