Просмотр исходного кода

test(challenge): 参与机制单元测试(respond/评分矩阵)

asus 1 месяц назад
Родитель
Сommit
d95ae678dc

+ 130 - 0
cfc-backend/src/test/java/com/etotem/cfc/service/ChallengeScoreServiceTest.java

@@ -0,0 +1,130 @@
+package com.etotem.cfc.service;
+
+import com.etotem.cfc.entity.FamilyChallengeScoreConfig;
+import com.etotem.cfc.entity.FamilyMember;
+import com.etotem.cfc.entity.FamilyRelationshipScore;
+import com.etotem.cfc.mapper.FamilyChallengeScoreConfigMapper;
+import com.etotem.cfc.mapper.FamilyMemberMapper;
+import com.etotem.cfc.mapper.FamilyRelationshipScoreMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ChallengeScoreServiceTest {
+
+    @Mock private FamilyRelationshipScoreMapper relationshipScoreMapper;
+    @Mock private FamilyChallengeScoreConfigMapper scoreConfigMapper;
+    @Mock private FamilyMemberMapper familyMemberMapper;
+    @Mock private EnergyService energyService;
+    @InjectMocks private ChallengeScoreService service;
+
+    @BeforeEach
+    void setUp() {
+        MockitoAnnotations.openMocks(this);
+        // 无配置行 → 用内置默认
+        when(scoreConfigMapper.selectOne(any())).thenReturn(null);
+    }
+
+    private FamilyRelationshipScore freshScore() {
+        FamilyRelationshipScore s = new FamilyRelationshipScore();
+        s.setId(1L);
+        s.setFamilyId(10L);
+        s.setFromMemberId(100L);
+        s.setToMemberId(200L);
+        s.setTrustScore(new BigDecimal("60.00"));
+        s.setIntimacyScore(new BigDecimal("60.00"));
+        s.setCommunicationScore(new BigDecimal("60.00"));
+        return s;
+    }
+
+    @Test
+    void applyAgree_shouldAddTrustIntimacyCommToOneDirectionOnly() {
+        FamilyRelationshipScore score = freshScore();
+        when(relationshipScoreMapper.selectOne(any())).thenReturn(score);
+
+        service.applyAgree(10L, 100L, Arrays.asList(100L, 200L), 1L);
+
+        assertEquals(new BigDecimal("61.00"), score.getTrustScore());
+        assertEquals(new BigDecimal("61.00"), score.getIntimacyScore());
+        assertEquals(new BigDecimal("61.00"), score.getCommunicationScore());
+        verify(relationshipScoreMapper).updateById(score);
+        verify(energyService).awardEnergyByCode(eq(100L), eq("action"), eq(1), anyString());
+    }
+
+    @Test
+    void applyReject_shouldFollowConfirmedMatrix() {
+        // I→X: trust-1/intimacy-1/comm-1
+        FamilyRelationshipScore iToX = freshScore();
+        iToX.setFromMemberId(100L); // I=100
+        iToX.setToMemberId(200L);   // X=200
+        // X→I: 仅 comm+1
+        FamilyRelationshipScore xToI = freshScore();
+        xToI.setFromMemberId(200L);
+        xToI.setToMemberId(100L);
+        // A→X: 仅 comm-1
+        FamilyRelationshipScore aToX = freshScore();
+        aToX.setFromMemberId(300L);
+        aToX.setToMemberId(200L);
+
+        when(relationshipScoreMapper.selectOne(any())).thenReturn(iToX, xToI, aToX);
+
+        service.applyReject(10L, 200L, 100L, Arrays.asList(300L), 1L);
+
+        // I→X
+        assertEquals(new BigDecimal("59.00"), iToX.getTrustScore());
+        assertEquals(new BigDecimal("59.00"), iToX.getIntimacyScore());
+        assertEquals(new BigDecimal("59.00"), iToX.getCommunicationScore());
+        // X→I
+        assertEquals(new BigDecimal("60.00"), xToI.getTrustScore());
+        assertEquals(new BigDecimal("60.00"), xToI.getIntimacyScore());
+        assertEquals(new BigDecimal("61.00"), xToI.getCommunicationScore());
+        // A→X(C3:只扣沟通)
+        assertEquals(new BigDecimal("60.00"), aToX.getTrustScore());
+        assertEquals(new BigDecimal("60.00"), aToX.getIntimacyScore());
+        assertEquals(new BigDecimal("59.00"), aToX.getCommunicationScore());
+
+        // 能量:I(100) 与 A(300) 各 -1
+        verify(energyService).deductEnergyByCode(eq(100L), eq("action"), eq(1), anyString());
+        verify(energyService).deductEnergyByCode(eq(300L), eq("action"), eq(1), anyString());
+    }
+
+    @Test
+    void applyInitiate_shouldNotAddTrust() {
+        FamilyRelationshipScore score = freshScore();
+        when(relationshipScoreMapper.selectOne(any())).thenReturn(score);
+
+        service.applyInitiate(10L, 100L, Arrays.asList(100L, 200L), 1L);
+
+        assertEquals(new BigDecimal("60.00"), score.getTrustScore()); // 不加信任
+        assertEquals(new BigDecimal("61.00"), score.getIntimacyScore());
+        assertEquals(new BigDecimal("61.00"), score.getCommunicationScore());
+    }
+
+    @Test
+    void getOrCreateScore_shouldUseMemberBaselineWhenNoRow() {
+        FamilyMember member = new FamilyMember();
+        member.setId(100L);
+        member.setTrustScore(new BigDecimal("70.00"));
+        member.setIntimacyScore(new BigDecimal("65.00"));
+        member.setCommunicationScore(new BigDecimal("55.00"));
+
+        when(relationshipScoreMapper.selectOne(any())).thenReturn(null);
+        when(familyMemberMapper.selectById(100L)).thenReturn(member);
+
+        service.applyAgree(10L, 100L, Arrays.asList(100L, 200L), 1L);
+
+        verify(relationshipScoreMapper).insert(any());
+    }
+}

+ 112 - 1
cfc-backend/src/test/java/com/etotem/cfc/service/FamilyChallengeServiceTest.java

@@ -2,8 +2,11 @@ package com.etotem.cfc.service;
 
 import com.etotem.cfc.common.Result;
 import com.etotem.cfc.entity.FamilyChallenge;
+import com.etotem.cfc.entity.FamilyChallengeParticipant;
 import com.etotem.cfc.entity.FamilyChallengeProgress;
+import com.etotem.cfc.entity.FamilyMember;
 import com.etotem.cfc.mapper.FamilyChallengeMapper;
+import com.etotem.cfc.mapper.FamilyChallengeParticipantMapper;
 import com.etotem.cfc.mapper.FamilyChallengeProgressMapper;
 import com.etotem.cfc.mapper.FamilyMemberMapper;
 import org.junit.jupiter.api.BeforeEach;
@@ -16,6 +19,7 @@ import java.util.Date;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -27,14 +31,17 @@ public class FamilyChallengeServiceTest {
 
     @Mock private FamilyChallengeMapper familyChallengeMapper;
     @Mock private FamilyChallengeProgressMapper familyChallengeProgressMapper;
+    @Mock private FamilyChallengeParticipantMapper familyChallengeParticipantMapper;
     @Mock private FamilyMemberMapper familyMemberMapper;
     @Mock private HealthScoreService healthScoreService;
     @Mock private PointsService pointsService;
+    @Mock private ChallengeScoreService challengeScoreService;
     @InjectMocks private FamilyChallengeService service;
 
     @BeforeEach
     void setUp() {
         MockitoAnnotations.openMocks(this);
+        when(familyChallengeParticipantMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
     }
 
     @Test
@@ -53,9 +60,15 @@ public class FamilyChallengeServiceTest {
         existing.setProgressValue(5);
         existing.setUpdatedAt(new Date());
 
+        FamilyChallengeParticipant participant = new FamilyChallengeParticipant();
+        participant.setChallengeId(1L);
+        participant.setMemberId(100L);
+        participant.setStatus("agreed");
+
         when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
         when(familyChallengeProgressMapper.selectOne(any())).thenReturn(existing);
         when(familyMemberMapper.selectCount(any())).thenReturn(1L);
+        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(participant);
 
         Result<Void> result = service.updateProgress(1L, 100L, 1);
 
@@ -126,8 +139,106 @@ public class FamilyChallengeServiceTest {
         when(familyMemberMapper.selectList(any())).thenReturn(java.util.Collections.emptyList());
         when(familyChallengeMapper.update(any(), any())).thenReturn(1);
 
-        service.getActiveChallenges(10L);
+        service.getActiveChallenges(10L, null);
 
         verify(familyChallengeMapper).update(any(), any());
     }
+
+    @Test
+    void respondChallenge_agree_shouldTransitionToActiveWhenAllAgreed() {
+        FamilyChallenge challenge = new FamilyChallenge();
+        challenge.setId(1L);
+        challenge.setFamilyId(10L);
+        challenge.setStatus("pending");
+        challenge.setTargetMode("aggregate");
+        challenge.setTargetValue(300);
+        challenge.setCreatorId(9L);
+
+        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
+        p.setId(1L);
+        p.setChallengeId(1L);
+        p.setMemberId(100L);
+        p.setStatus("pending");
+
+        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
+        initiator.setId(2L);
+        initiator.setChallengeId(1L);
+        initiator.setMemberId(200L);
+        initiator.setStatus("agreed");
+
+        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
+        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
+        when(familyChallengeParticipantMapper.selectList(any()))
+                .thenReturn(java.util.Arrays.asList(initiator, p));
+
+        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
+
+        assertEquals(Integer.valueOf(200), result.getCode());
+        verify(challengeScoreService).applyAgree(eq(10L), eq(100L), anyList(), eq(1L));
+        verify(familyChallengeParticipantMapper).updateById(argThat(pp -> "agreed".equals(pp.getStatus())));
+        verify(familyChallengeMapper).updateById(argThat(c -> "active".equals(c.getStatus())));
+    }
+
+    @Test
+    void respondChallenge_reject_shouldCancelWhenOnlyInitiatorLeft() {
+        FamilyChallenge challenge = new FamilyChallenge();
+        challenge.setId(1L);
+        challenge.setFamilyId(10L);
+        challenge.setStatus("pending");
+        challenge.setTargetMode("aggregate");
+        challenge.setTargetValue(300);
+        challenge.setCreatorId(9L);
+
+        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
+        p.setId(1L);
+        p.setChallengeId(1L);
+        p.setMemberId(100L);
+        p.setStatus("pending");
+
+        FamilyChallengeParticipant initiator = new FamilyChallengeParticipant();
+        initiator.setId(2L);
+        initiator.setChallengeId(1L);
+        initiator.setMemberId(200L);
+        initiator.setStatus("agreed");
+
+        FamilyMember member = new FamilyMember();
+        member.setId(200L);
+        member.setUserId(9L);
+
+        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
+        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
+        when(familyChallengeParticipantMapper.selectList(any()))
+                .thenReturn(java.util.Arrays.asList(initiator, p));
+        when(familyMemberMapper.selectList(any())).thenReturn(java.util.Arrays.asList(member));
+
+        Result<Void> result = service.respondChallenge(1L, 100L, "reject");
+
+        assertEquals(Integer.valueOf(200), result.getCode());
+        verify(challengeScoreService).applyReject(eq(10L), eq(100L), eq(200L), anyList(), eq(1L));
+        verify(familyChallengeMapper).updateById(argThat(c -> "cancelled".equals(c.getStatus())));
+    }
+
+    @Test
+    void respondChallenge_shouldRejectWhenAlreadyProcessed() {
+        FamilyChallenge challenge = new FamilyChallenge();
+        challenge.setId(1L);
+        challenge.setFamilyId(10L);
+        challenge.setStatus("pending");
+        challenge.setTargetMode("aggregate");
+        challenge.setTargetValue(300);
+
+        FamilyChallengeParticipant p = new FamilyChallengeParticipant();
+        p.setId(1L);
+        p.setChallengeId(1L);
+        p.setMemberId(100L);
+        p.setStatus("agreed"); // 已处理过
+
+        when(familyChallengeMapper.selectById(1L)).thenReturn(challenge);
+        when(familyChallengeParticipantMapper.selectOne(any())).thenReturn(p);
+
+        Result<Void> result = service.respondChallenge(1L, 100L, "agree");
+
+        assertEquals(Integer.valueOf(500), result.getCode());
+        verify(challengeScoreService, never()).applyAgree(any(), any(), any(), any());
+    }
 }