|
|
@@ -0,0 +1,168 @@
|
|
|
+package com.etotem.cfc.service;
|
|
|
+
|
|
|
+import com.etotem.cfc.entity.FamilyMembership;
|
|
|
+import com.etotem.cfc.entity.User;
|
|
|
+import com.etotem.cfc.mapper.FamilyMembershipMapper;
|
|
|
+import com.etotem.cfc.mapper.MembershipLevelMapper;
|
|
|
+import com.etotem.cfc.mapper.UserMapper;
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
+import org.mockito.Mock;
|
|
|
+import org.mockito.Mockito;
|
|
|
+import org.mockito.MockitoAnnotations;
|
|
|
+
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.util.Date;
|
|
|
+
|
|
|
+import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
+import static org.mockito.Mockito.doReturn;
|
|
|
+import static org.mockito.Mockito.when;
|
|
|
+
|
|
|
+/**
|
|
|
+ * MemberLevelQueryService 单元测试(纯单元测试,无 SpringBootTest,避免 MySQL 连接)。
|
|
|
+ *
|
|
|
+ * 说明:本服务由 MembershipService 下沉而来(getMemberLevel / getLevelOrder 逐行等价搬迁,
|
|
|
+ * 唯一事实源,只依赖 Mapper、不依赖任何 Service)。本测试覆盖搬迁前后必须逐分支等价的核心语义:
|
|
|
+ * <ol>
|
|
|
+ * <li>PROVIDER → FREE(服务商为独立角色,不构成会员等级)</li>
|
|
|
+ * <li>FAMILY 过期 → FREE(含 member_expire_time 校验)</li>
|
|
|
+ * <li>个人/家庭取高(含 FREE/BASIC 同级 tie-break 优先非 FREE)</li>
|
|
|
+ * <li>未知等级回退 1(level_order 缺失或空/未知 code)</li>
|
|
|
+ * </ol>
|
|
|
+ *
|
|
|
+ * level_code → level_order 属于配置数据而非被测逻辑,通过 spy stub getLevelOrder 提供
|
|
|
+ * (与生产 membership_levels 数据一致:FREE=1 BASIC=1 FAMILY=2 PROVIDER=3 PREMIUM=4 LIFETIME=5)。
|
|
|
+ */
|
|
|
+public class MemberLevelQueryServiceTest {
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private UserMapper userMapper;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private FamilyMembershipMapper membershipMapper;
|
|
|
+
|
|
|
+ @Mock
|
|
|
+ private MembershipLevelMapper levelMapper;
|
|
|
+
|
|
|
+ private MemberLevelQueryService service;
|
|
|
+
|
|
|
+ @BeforeEach
|
|
|
+ public void setUp() {
|
|
|
+ MockitoAnnotations.openMocks(this);
|
|
|
+ MemberLevelQueryService raw = new MemberLevelQueryService();
|
|
|
+ setField(raw, "userMapper", userMapper);
|
|
|
+ setField(raw, "membershipMapper", membershipMapper);
|
|
|
+ setField(raw, "levelMapper", levelMapper);
|
|
|
+ service = Mockito.spy(raw);
|
|
|
+ doReturn(1).when(service).getLevelOrder("FREE");
|
|
|
+ doReturn(1).when(service).getLevelOrder("BASIC");
|
|
|
+ doReturn(2).when(service).getLevelOrder("FAMILY");
|
|
|
+ doReturn(3).when(service).getLevelOrder("PROVIDER");
|
|
|
+ doReturn(4).when(service).getLevelOrder("PREMIUM");
|
|
|
+ doReturn(5).when(service).getLevelOrder("LIFETIME");
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setField(Object target, String fieldName, Object value) {
|
|
|
+ try {
|
|
|
+ Field f = target.getClass().getDeclaredField(fieldName);
|
|
|
+ f.setAccessible(true);
|
|
|
+ f.set(target, value);
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private User user(Long id, String level, Date expire, Long familyId) {
|
|
|
+ User u = new User();
|
|
|
+ u.setId(id);
|
|
|
+ u.setMemberLevel(level);
|
|
|
+ u.setMemberExpireTime(expire);
|
|
|
+ u.setFamilyId(familyId);
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+
|
|
|
+ private FamilyMembership activeMembership(String code) {
|
|
|
+ FamilyMembership fm = new FamilyMembership();
|
|
|
+ fm.setLevelCode(code);
|
|
|
+ fm.setPaymentStatus("paid");
|
|
|
+ fm.setEndDate(future());
|
|
|
+ return fm;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Date future() {
|
|
|
+ return new Date(System.currentTimeMillis() + 86_400_000L);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Date past() {
|
|
|
+ return new Date(System.currentTimeMillis() - 86_400_000L);
|
|
|
+ }
|
|
|
+
|
|
|
+ // ── 分支1:PROVIDER → FREE ──────────────────────────────────────────
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_provider_returnsFree() {
|
|
|
+ // 服务商为独立角色,不构成会员等级身份;即便家庭侧有更高会员也按 FREE 参与比较
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "PROVIDER", future(), null));
|
|
|
+ assertEquals("FREE", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_nullUser_returnsFree() {
|
|
|
+ when(userMapper.selectById(999L)).thenReturn(null);
|
|
|
+ assertEquals("FREE", service.getMemberLevel(999L));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ── 分支2:FAMILY 过期 → FREE ────────────────────────────────────────
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_familyExpired_returnsFree() {
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "FAMILY", past(), null));
|
|
|
+ assertEquals("FREE", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ── 分支3:个人/家庭取高 ─────────────────────────────────────────────
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_personalHigher_thanFamily_returnsPersonal() {
|
|
|
+ // 个人 PREMIUM(4) > 家庭 FAMILY(2)
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "PREMIUM", future(), 10L));
|
|
|
+ when(membershipMapper.selectOne(any())).thenReturn(activeMembership("FAMILY"));
|
|
|
+ assertEquals("PREMIUM", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_familyHigher_thanPersonal_returnsFamily() {
|
|
|
+ // 家庭 PREMIUM(4) > 个人 FREE(1)
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "FREE", null, 10L));
|
|
|
+ when(membershipMapper.selectOne(any())).thenReturn(activeMembership("PREMIUM"));
|
|
|
+ assertEquals("PREMIUM", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_tieBetweenFreeAndBasic_prefersNonFree() {
|
|
|
+ // FREE 与 BASIC 同为 level_order=1,平级时优先非 FREE 一侧
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "FREE", null, 10L));
|
|
|
+ when(membershipMapper.selectOne(any())).thenReturn(activeMembership("BASIC"));
|
|
|
+ assertEquals("BASIC", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getMemberLevel_noFamilyRecord_usesPersonalLevel() {
|
|
|
+ when(userMapper.selectById(1L)).thenReturn(user(1L, "FAMILY", future(), null));
|
|
|
+ assertEquals("FAMILY", service.getMemberLevel(1L));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ── 分支4:未知等级回退 1 ────────────────────────────────────────────
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getLevelOrder_unknownCode_fallsBackToOne() {
|
|
|
+ assertEquals(1, service.getLevelOrder("UNKNOWN"));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void getLevelOrder_nullOrEmpty_fallsBackToOne() {
|
|
|
+ assertEquals(1, service.getLevelOrder(null));
|
|
|
+ assertEquals(1, service.getLevelOrder(""));
|
|
|
+ }
|
|
|
+}
|