# 测试执行流程

WesPy 活动埋点测试的完整7步执行流程和 Widget 埋点测试标准。

---

## 📋 测试执行流程概览

### 第一步：获取测试用例信息，剔除非服务器埋点
### 第二步：通过 get_key_api 查询活动配置
### 第三步：定位埋点代码（活动代码 + Widget代码）
### 第四步：详细执行每一条测试用例
### 第五步：多场景测试（扩展验证）
### 第六步：记录测试结果（每条用例都记录）
### 第七步：按照模板输出测试执行报告

---

## 第一步：获取测试用例信息，剔除非服务器埋点

**1.1 读取测试用例文档**

从测试用例文档中提取所有埋点信息：
- [ ] 埋点名称（如"夺宝开奖"）
- [ ] 事件名称（ActivityTotal / AppClick / AppViewScreen / ShowH5）
- [ ] action 值（如 "hunt_room"）
- [ ] 所有字段列表及类型
- [ ] 触发条件（如：完成任务、领取奖励）
- [ ] 业务场景（个人维度、房间维度等）

**1.2 过滤服务器埋点（关键！）**

只测试服务器埋点，剔除客户端埋点：

**✅ 需要测试（服务器埋点）**:
- `ActivityTotal` - 所有活动埋点（后端上报）

**❌ 不需要测试（客户端埋点）**:
- `AppClick` - 客户端点击埋点
- `AppViewScreen` - 客户端页面曝光埋点
- `ShowH5` - 前端H5埋点

**过滤示例**：

```markdown
原始测试用例（26个）：
1. ❌ 礼包弹窗曝光——客户端 (AppViewScreen) - 跳过
2. ❌ 礼包购买点击——客户端 (AppClick) - 跳过
3. ✅ 完成任务（累消任务） (ActivityTotal) - 需要测试
4. ✅ 领取奖励（累消任务） (ActivityTotal) - 需要测试
...
26. ❌ 【前端】超过好友弹窗曝光&点击 (ShowH5) - 跳过

过滤后（23个）：
只测试 ActivityTotal 事件
```

**1.3 生成测试清单**

创建待测试埋点清单：

| # | 埋点名称 | action | activity_type | 优先级 |
|---|---------|--------|---------------|--------|
| TC03 | 完成任务（累消任务） | complete_task | task | P0 |
| TC04 | 领取奖励（累消任务） | recv_reward | task | P0 |
| TC05 | 家族完成任务 | complete_task | temporary_event | P0 |
| ... | ... | ... | ... | ... |

---

## 第二步：通过 get_key_api 查询活动配置

**🔴 强制要求 - 每次必做**

- **必须查询配置** - 每次测试活动埋点时，都必须通过 get_key_api 查询活动配置
- **信息不全必须问** - 如果不知道活动ID或区服，**必须先问用户**，不能猜测或跳过
- **不能省略此步骤** - 即使认为配置肯定存在，也必须查询验证

**必查信息**：
1. **活动ID** - 如果用户未提供，必须询问
2. **区服（Region）** - 如果用户未提供，必须询问（C/A/E/J/K/R）
3. **配置存在性** - 确认活动在配置中心有数据
4. **Widget配置** - 确认启用了哪些Widget

**示例对话**：
- 用户："测试这个活动的埋点"
- 你："好的，请问活动ID是多少？区服是哪个（C/A/E/J/K/R）？"

---

**2.1 使用配置查询工具**

```bash
cd scripts

# 交互式查询
python3 get_key_api.py

# 或命令行直接查询
python3 -c "from get_key_api import get_activity_config; \
    import json; \
    config = get_activity_config(6360, 'C'); \
    print(json.dumps(config, indent=2, ensure_ascii=False))"
```

**2.2 验证关键配置**

- [ ] **活动配置存在** - 确认活动ID在配置中心有数据
- [ ] **Widget配置** - 验证启用了哪些Widget（盲盒、抽奖、任务等）
- [ ] **任务配置** - 确认任务ID、阶段ID、任务名称
- [ ] **奖励配置** - 检查奖池ID、道具ID、奖励类型
- [ ] **枚举值** - 验证 box_type、lottery_type 等枚举值

**2.3 记录配置信息**

```markdown
## 活动配置信息

**活动ID**: 6360
**活动名称**: 五周年三阶段
**活动类型**: 集合页活动

### Widget配置
- ✅ 任务系统：启用（task_widget）
- ✅ 家族任务：启用（family_task_widget）
- ✅ 抽奖系统：启用（lottery_widget）
- ✅ 盲盒系统：启用（blind_box_widget）
- ❌ 夺宝系统：未启用

### 任务配置
- 任务ID范围：1-10
- 阶段数：3个阶段
- 周期类型：0=活动累计，1=每日

### 奖励配置
- 奖池类型：1=小奖池，2=大奖池
- 抽奖币ID：10001
```

---

## 第三步：定位埋点代码（活动代码 + Widget代码）

**3.1 查找活动目录**

```bash
# 按活动名称查找
find wespy-http-go/app/activity/2026 -name "*annual*" -o -name "*6360*"

# 或按活动ID查找
grep -r "act_id.*6360" wespy-http-go/app/activity/2026/
```

**3.2 定位活动埋点代码**

```bash
cd {activity_dir}

# 查找 acttrack 目录
find . -name "acttrack" -type d

# 查看埋点文件
ls -la acttrack/
# 输出：acttrack/sale.go 或 acttrack/acttrack.go

# 查看所有埋点函数
grep -rn "func Track" acttrack/
```

**3.3 定位 Widget 埋点代码（重要！）**

很多埋点在 Widget 的公共代码中，不在活动目录：

```bash
# 查找 Widget 埋点代码位置
cd wespy-http-go/app/activity/widget

# 常见 Widget 埋点目录：
# - widget/task/acttrack/          # 任务埋点
# - widget/lottery/acttrack/       # 抽奖埋点
# - widget/blind_box/acttrack/     # 盲盒埋点
# - widget/chip/acttrack/          # 碎片/兑换埋点
# - widget/gift/acttrack/          # 礼物埋点

# 搜索特定 action
grep -r "complete_task" widget/*/acttrack/
grep -r "recv_reward" widget/*/acttrack/
grep -r "do_wheel_lottery" widget/*/acttrack/
```

**3.4 检查 action 唯一性（关键！）**

```bash
# 检查活动埋点的 action
cd {activity_dir}
grep -rh '"action"' acttrack/*.go | awk -F'"' '{print $4}' | sort | uniq -c

# 检查 Widget 埋点的 action（如果使用了Widget）
cd wespy-http-go/app/activity/widget
grep -rh '"action"' */acttrack/*.go | awk -F'"' '{print $4}' | sort | uniq -c

# 如果发现重复，必须修复
```

**3.5 创建埋点代码映射表**

| 测试用例 | action | 代码位置 | 类型 |
|---------|--------|---------|------|
| TC03 | complete_task | widget/task/acttrack/task.go:45 | Widget |
| TC04 | recv_reward | widget/task/acttrack/task.go:78 | Widget |
| TC05 | complete_task | activity_6360/acttrack/sale.go:120 | 活动 |
| TC11 | hunt_room | activity_6360/acttrack/sale.go:200 | 活动 |

---

## 第四步：详细执行每一条测试用例

**重要性**: 🔴 Critical - 在测试执行前必须先查询配置，验证代码中使用的配置值是否与生产环境一致

---

### ⭐ Widget 埋点测试标准（🔴 强制要求 - 绝对不能偷懒）

**📖 参考文档**: [Widget埋点测试方法总结](../docs/Widget埋点测试方法总结.md) - 包含详细的测试流程、代码位置规律、4种常见模式、实战案例

**用户要求（2026-03-19）**: Widget 埋点即使有配置，也**必须展开详细测试用例表格，逐字段验证**

⚠️ **严重警告**: 不允许以"Widget埋点通过代码审查"为由跳过详细测试！

**强制要求清单** - 每个Widget埋点必须完成：
- [ ] ✅ **展开详细测试用例表格** - 不能只说"通过审查"
- [ ] ✅ **逐字段验证** - 每个字段必须单独一行测试用例
- [ ] ✅ **代码验证片段** - 必须展示Widget代码实现
- [ ] ✅ **测试数据示例** - 必须包含JSON格式和表格格式
- [ ] ✅ **验证配置数据** - 从配置中心查询并验证枚举值

**违反后果**:
- ❌ 报告不完整，无法通过审核
- ❌ 可能遗漏字段错误、类型错误、逻辑错误
- ❌ 不符合测试标准，需要返工重做

#### 错误做法 ❌

```markdown
### Widget埋点通用审查

**相关埋点**: #7, #13, #15, #16, #19
**代码位置**: [common/acttrack/lottery.go:106]

所有 Lottery Widget 埋点通过代码审查。
```

**问题** - 以下做法**绝对不可接受**:
- ❌ 没有展开详细测试用例 - 只说"通过审查"
- ❌ 没有逐字段验证 - 只说"字段完整"
- ❌ 没有提供测试数据示例 - 只说"配置正确"
- ❌ 假设 Widget 代码正确就不详细测试
- ❌ 只列出代码位置，不展开测试用例表格
- ❌ 只验证了部分字段，其他字段说"同上"
- ❌ 没有验证自动计算字段的逻辑
- ❌ 没有从配置中心查询验证枚举值

**为什么这些做法不可接受**:
1. Widget代码也可能有bug，不能假设正确
2. 配置中心的值可能与代码不匹配（如box_type=2 vs 需求=1）
3. 自动计算字段可能逻辑错误（如金币价值计算）
4. 字段类型可能不匹配（如STRING vs int32）
5. 枚举值可能不完整或错误

#### 正确做法 ✅

```markdown
### 📋 #7: 获得奖池不同奖励的人数、次数（抽奖）

**代码位置**: [common/acttrack/lottery.go:106]
**调用位置**: Widget通用调用

| 用例ID | 测试场景 | 预期结果 | 预测结果（代码审查） | 状态 | 问题 |
|--------|---------|---------|---------------------|------|------|
| TC07-01 | 抽奖时上报 | action="do_wheel_lottery" | action="do_wheel_lottery"✅ (lottery.go:132) | ✅ | - |
| TC07-02 | activity_type固定值 | activity_type="lottery" | "lottery"✅ (lottery.go:131) | ✅ | - |
| TC07-03 | 包含box_type字段 | box_type=抽奖类型 | data.BoxType✅ (lottery.go:136) | ✅ | - |
| TC07-04 | 包含lottery_num字段 | lottery_num=抽奖次数(1/10/30) | data.LotteryNum✅ (lottery.go:144) | ✅ | - |
| TC07-05 | 包含use_lottery_coins字段 | use_lottery_coins=消耗抽奖币数量 | data.UseLotteryCoins✅ (lottery.go:145) | ✅ | - |
| TC07-06 | 自动计算use_lottery_coins_num | use_lottery_coins_num=金币价值 | 计算totalPrice✅ (lottery.go:164-174) | ✅ | - |
| TC07-07 | 包含is_free字段 | is_free=0/1 | data.IsFree✅ (lottery.go:135) | ✅ | - |
| TC07-08 | 包含is_use_lottery_coin字段 | is_use_lottery_coin=bool | data.IsUseLotteryCoin✅ (lottery.go:156) | ✅ | - |
| TC07-09 | 包含reward_type字段 | reward_type=奖励类型 | data.RewardType✅ (lottery.go:138) | ✅ | - |
| TC07-10 | 包含reward_id字段 | reward_id=奖励ID | data.RewardId✅ (lottery.go:140) | ✅ | - |
| TC07-11 | 包含reward_name字段 | reward_name=奖励名称 | data.RewardName✅ (lottery.go:141) | ✅ | - |
| TC07-12 | 包含reward_num字段 | reward_num=奖励数量 | data.RewardNum✅ (lottery.go:142) | ✅ | - |

**小计**: 12个用例，✅ **12个通过**

**代码验证**:
```go
// common/acttrack/lottery.go:106-189
func TrackDoLottery(actId, uid int, data LotteryReward) {
    // ... 团队信息计算 ...
    trackData := map[string]interface{}{
        "activity_type":       "lottery",              // ✅ 固定值
        "action":              "do_wheel_lottery",     // ✅ 固定值
        "act_id":              actId,
        "is_free":             data.IsFree,            // ✅ 是否免费
        "box_type":            data.BoxType,           // ✅ 抽奖类型
        "reward_id":           data.RewardId,          // ✅ 奖励ID
        "reward_name":         data.RewardName,        // ✅ 奖励名称
        "reward_num":          data.RewardNum,         // ✅ 奖励数量
        "lottery_num":         data.LotteryNum,        // ✅ 抽奖次数
        "use_lottery_coins":   data.UseLotteryCoins,   // ✅ 消耗抽奖币
        "is_use_lottery_coin": data.IsUseLotteryCoin,  // ✅ bool类型
        // ... 其他字段 ...
    }
    // ✅ 自动计算 use_lottery_coins_num（金币价值）
    var totalPrice int
    for k, v := range data.ChipCostMap {
        price, _ := actreward.GetRewardPrice(...)
        totalPrice += int(price)
    }
    trackData["use_lottery_coins_num"] = totalPrice

    SensorTrack(int64(uid), "ActivityTotal", trackData, ...)
}
```

#### 📊 测试数据示例（#7 抽奖）

**操作步骤**:
```
1. 用户uid=100001
2. 进行大奖池抽奖
3. 抽1次，消耗10个抽奖币
4. 获得奖励：心动礼物卡×1
```

**预期埋点数据**:
```json
{
  "event_name": "ActivityTotal",
  "distinct_id": "100001",
  "properties": {
    "action": "do_wheel_lottery",
    "activity_type": "lottery",
    "act_id": 6362,
    "box_type": 1,
    "lottery_num": 1,
    "use_lottery_coins": 10,
    "use_lottery_coins_num": 5000,
    "is_free": 0,
    "is_use_lottery_coin": true,
    "reward_type": "prop",
    "reward_id": 1010012,
    "reward_name": "心动礼物卡",
    "reward_num": 1
  }
}
```

**预期输出示例**:
| user_id | box_type | lottery_num | reward_id | reward_name | reward_num | time                |
|---------|----------|-------------|-----------|-------------|------------|---------------------|
| 100001  | 1        | 1           | 1010012   | 心动礼物卡   | 1          | 2026-03-19 15:30:45 |
| 100002  | 2        | 10          | 3         | 戒指        | 1          | 2026-03-19 15:28:12 |

**关键验证点**:
- ✅ `use_lottery_coins_num` 自动计算金币价值
- ✅ `is_use_lottery_coin` 为bool类型
- ✅ `lottery_num` 取值为1/10/30
```

#### Widget 埋点测试要求汇总 🔴 强制

**核心原则**: Widget埋点和普通埋点一样，必须逐字段展开测试，不能因为是Widget就假设代码正确！

**必须包含的内容**（缺一不可）:
1. ✅ **测试用例表格** 🔴 - **必须逐字段展开**，每个字段单独一行测试用例
   - action 固定值验证
   - activity_type 固定值验证
   - 每个业务字段单独验证（包含字段、触发时机、枚举值等）
   - 自动计算字段的逻辑验证
   - 边界场景测试（is_free=0/1, lottery_num=1/10等）

2. ✅ **代码验证片段** 🔴 - 展示 Widget 代码实现，标注行号
   - 必须复制实际代码，不能只说"代码正确"
   - 必须标注文件路径和行号
   - 必须标注每个字段的来源（参数/自动计算/配置）

3. ✅ **测试数据示例** 🔴 - 包含完整的测试场景
   - 操作步骤（用户做什么动作触发埋点）
   - 预期JSON格式数据（完整的埋点数据结构）
   - 预期表格输出（数数平台查询格式）
   - 关键验证点（自动计算逻辑、枚举值、类型等）

4. ✅ **小计统计** - 每个埋点后统计通过/失败数量
   - 格式：`**小计**: X个用例，✅ **X个通过**，⚠️ **X个Warning**`

5. ✅ **配置验证** 🔴 - 从配置中心查询实际配置
   - 验证枚举值（box_type, lottery_num等）
   - 验证配置项存在性（tasks, lottery, blind_box等）
   - 验证配置值与代码逻辑一致

**Widget 埋点类型**:
- 任务埋点 (task.go) - TrackCompleteTask, TrackGetTaskReward
- 抽奖埋点 (lottery.go) - TrackDoLottery, TrackLotteryGurantee
- 收集碎片埋点 (collect_chip.go) - TrackCollectChipAddChip
- 兑换商城埋点 (exchange_store.go) - TrackExchangeGood
- 礼盒埋点 (gift_box.go) - TrackGiftBoxGetReward
- 盲盒埋点 (blind_box.go) - TrackBlindBoxGetReward
- 送礼埋点 (send_gift.go) - TrackSendGift

**测试用例数量要求**（最低标准）:
- 任务埋点: ≥6个用例（字段完整性 + action验证）
- 抽奖埋点: ≥12个用例（字段完整性 + 计算逻辑）
- 收集碎片: ≥8个用例（字段 + 团队信息 + 金币计算）
- 兑换商城: ≥11个用例（字段 + 团队信息）
- 礼盒/盲盒: ≥10个用例（字段 + 概率档位）
- 送礼: ≥10个用例（字段 + action动态变化）
- 充值优惠: ≥7个用例（字段 + 事件触发机制）
- 红包雨: ≥9个用例（字段 + 触发条件）

**逐字段验证检查清单** 🔴 必须每个Widget埋点都完成：

基础字段（必测）:
- [ ] action 固定值或动态切换逻辑
- [ ] activity_type 固定值
- [ ] act_id 活动ID传递

Widget特有字段（根据类型）:
- [ ] 任务: task_id, task_name, period_type, stage
- [ ] 抽奖: box_type, lottery_num, use_lottery_coins, use_lottery_coins_num（自动计算）
- [ ] 碎片: chip_id, chip_value（正/负）, chip_name（自动获取）, source
- [ ] 兑换: reward_id, reward_name, reward_num, chip_id, chip_value
- [ ] 送礼: gift_id, origin_gift_id, origin_gift_price, condition, IsGuarantee/IsRandom标志
- [ ] 红包雨: type, coin, rid, origin_gift_id, trigger_buff

自动字段（必须验证逻辑）:
- [ ] use_lottery_coins_num - 如何计算金币价值
- [ ] chip_name - 如何从配置获取
- [ ] team_key, team_num, uids - 团队信息如何自动获取
- [ ] activity, activity_name - 如何自动填充

**成功案例参考**:
- `/reports/五周年三阶段_埋点测试执行报告_6362_6420_2026-03-19.md`
  - TC03-TC04: 任务埋点详细展开
  - TC07: 抽奖埋点12个字段逐个验证
  - TC18/TC23: 碎片和兑换埋点详细测试
  - TC12/TC14: 盲盒礼盒详细测试，还发现了字段缺失问题
- `/reports/欧洲-樱之神国_埋点测试执行报告_6392_2026-03-20.md`
  - #1 充值优惠: 7个用例，事件触发机制验证
  - #12-14 礼物: 12个用例，发现智能action切换机制
  - #15 红包雨: 9个用例，Widget实现规范

#### 🔍 Widget测试合格快速检查（自查清单）

**在提交报告前，对每个Widget埋点检查以下5点**:

1. **是否有详细测试用例表格？** 🔴
   - ✅ 合格: 有表格，每个字段一行，≥6个用例
   - ❌ 不合格: 只说"通过审查"，没有表格

2. **是否逐字段验证？** 🔴
   - ✅ 合格: action, activity_type, act_id, 所有业务字段都单独验证
   - ❌ 不合格: 只验证了部分字段，其他说"同上"

3. **是否有代码验证片段？** 🔴
   - ✅ 合格: 展示了实际代码，标注了行号和文件路径
   - ❌ 不合格: 只说"代码正确"，没有展示代码

4. **是否有测试数据示例？** 🔴
   - ✅ 合格: 包含操作步骤、JSON数据、表格输出、关键验证点
   - ❌ 不合格: 没有测试数据，或只有JSON没有验证点

5. **是否验证了配置？** 🔴
   - ✅ 合格: 查询了配置中心，验证了枚举值和配置项
   - ❌ 不合格: 没有查配置，或查了但没有在测试中体现

**判断标准**: 5个检查点**全部✅** → 合格；**任意一个❌** → 不合格，需要补充

**不合格的报告必须返工！**

---

### 普通埋点测试流程

**4.1 代码审查（先审查后测试）**

在实际触发埋点前，先审查代码：

**步骤1：查看埋点函数定义**
```bash
# 查看特定埋点函数
cat acttrack/sale.go | grep -A 30 "func TrackFamilyCompleteTask"
```

**步骤2：对照字段完整性**

| 字段名 | 需求要求 | 代码实现 | 状态 |
|--------|---------|---------|------|
| activity_type | temporary_event | ✅ | ✅ |
| action | complete_task | ✅ | ✅ |
| act_id | NUMBER | ✅ actId | ✅ |
| task_id | NUMBER | ✅ taskId | ✅ |
| task_name | STRING | ✅ taskName | ✅ |
| stage | NUMBER | ✅ stageId | ✅ |
| family_id | NUMBER | ✅ familyId | ✅ |

**步骤3：检查常见Bug**
- [ ] 字段值是否硬编码（如：`reward_num: 2026`）
- [ ] 字段是否缺失
- [ ] 条件判断是否正确

**步骤4：查找调用点**
```bash
# 搜索埋点函数在哪里调用
grep -rn "TrackFamilyCompleteTask" .

# 验证调用时机是否正确
```

**4.2 触发埋点**

按照测试用例操作步骤，实际触发埋点：

```
示例：TC05 - 家族完成任务

操作步骤：
1. 使用测试账号登录
2. 加入测试家族
3. 消耗金币达到任务目标（如：消耗10000金币）
4. 等待任务完成触发埋点
```

**4.3 抓包验证（重要！）**

使用Charles/Fiddler抓包：

```json
// 查找 sensorsdata.track 请求
// 验证JSON数据：

POST /track HTTP/1.1
Host: sensors-api.xxx.com
Content-Type: application/json

{
  "event": "ActivityTotal",
  "properties": {
    "activity_type": "temporary_event",
    "action": "complete_task",          // ✅ 验证action
    "act_id": 6360,                     // ✅ 验证活动ID
    "task_id": 1,                       // ✅ 验证任务ID
    "task_name": "累消任务",             // ✅ 验证任务名
    "stage": 1,                         // ✅ 验证阶段
    "family_id": 12345                  // ✅ 验证家族ID
  },
  "distinct_id": "100001"               // ✅ 验证用户ID
}
```

**验证清单**:
- [ ] 埋点有上报（抓包能看到请求）
- [ ] 事件名称正确（ActivityTotal）
- [ ] action值正确（如：complete_task）
- [ ] 所有需求字段都存在
- [ ] 字段值正确（不是null、不是硬编码的错误值）
- [ ] 用户ID正确（distinct_id）

**4.4 数数平台验证**

登录数数平台，执行查询验证：

**查询1：验证数据存在**
```sql
-- 查询最近的埋点数据
SELECT *
FROM ActivityTotal
WHERE act_id = 6360
    AND action = 'complete_task'
    AND date >= CURRENT_DATE
ORDER BY time DESC
LIMIT 10;
```

**查询2：验证字段值多样性（防止硬编码）**
```sql
-- 验证字段值的多样性
SELECT
    task_id,
    stage,
    family_id,
    COUNT(*) as cnt
FROM ActivityTotal
WHERE act_id = 6360
    AND action = 'complete_task'
    AND date >= CURRENT_DATE
GROUP BY task_id, stage, family_id;

-- 预期：task_id、stage、family_id 有多样化的值，不是全部一样
```

**查询3：验证上报次数**
```sql
-- 验证单次操作的上报次数
SELECT
    DATE_FORMAT(time, '%H:%i:%s') as trigger_time,
    COUNT(*) as report_count
FROM ActivityTotal
WHERE act_id = 6360
    AND action = 'complete_task'
    AND distinct_id = '100001'  -- 测试账号
    AND date >= CURRENT_DATE
GROUP BY trigger_time
ORDER BY trigger_time DESC;

-- 预期：每次操作只上报1次（除非设计就是多次）
```

**验证清单**:
- [ ] 数数平台能查询到数据（延迟通常5-10分钟）
- [ ] 字段值正确（与抓包数据一致）
- [ ] 字段值有多样性（不是硬编码）
- [ ] 上报次数正确（单次操作上报1次，除非特殊设计）
- [ ] 时间戳正确（与操作时间一致）

**4.5 单条用例测试结论**

记录测试结果：

```markdown
### TC05: 家族完成任务

#### 代码审查
- ✅ 字段完整性：通过（所有字段都实现）
- ✅ 无硬编码：通过
- ✅ 调用时机正确：在任务完成时触发

#### 实际测试
- ✅ 抓包验证：通过
- ✅ 数数平台查询：通过（延迟3分钟）
- ✅ 字段值正确：所有字段值符合预期
- ✅ 上报次数：1次

**结论**: ✅ 通过
```

---

## 第五步：多场景测试（扩展验证）

完成基础测试后，针对特殊场景进行扩展测试。

**5.1 边界场景测试**

| 场景 | 测试内容 | 预期结果 |
|-----|---------|---------|
| 最小值 | 任务刚完成（进度100%） | ✅ 上报 |
| 临界值 | 任务超额完成（进度150%） | ✅ 上报 |
| 异常值 | 任务未完成（进度50%） | ❌ 不上报 |
| 边界值 | 奖励数量为0 | 验证字段值正确 |

**5.2 不同维度测试**

以TC11（夺宝开奖）为例：

| 测试场景 | type_str | 预期rid字段 | 预期uid字段 | 实际结果 |
|---------|---------|------------|------------|---------|
| 个人维度 | "个人维度" | 不存在 | 获奖用户ID | [填写] |
| 房间维度 | "房间维度" | 房间ID>0 | Top用户ID | [填写] |

**5.3 枚举值完整性测试**

对于有枚举值的字段，必须逐一测试：

```markdown
示例：box_type 字段

需求定义：1=小奖池，2=大奖池

测试场景：
- [ ] box_type=1：使用小奖池抽奖，验证上报值为1
- [ ] box_type=2：使用大奖池抽奖，验证上报值为2
```

**5.4 多用户/多次上报测试**

对于排名类、批量类埋点：

```markdown
示例：TC06 - 家族贡献top5

测试场景：
- 家族任务完成后，验证为 top5 每个用户都上报
- 预期上报次数：5次（rank=1,2,3,4,5）
- 验证每条数据的 rank、uid、use_coin 字段正确
```

**5.5 异常场景测试**

| 场景 | 测试内容 | 预期结果 |
|-----|---------|---------|
| 金币不足 | 抽奖金币不足 | ❌ 不上报 |
| 权限不足 | 非家族成员完成任务 | ❌ 不上报或字段不同 |
| 活动未开始 | 活动开始前操作 | ❌ 不上报 |
| 活动已结束 | 活动结束后操作 | ❌ 不上报 |

---

## 第六步：记录测试结果（每条用例都记录）

为每条测试用例记录详细的测试结果，包括代码审查、实际测试、发现问题等。

**6.1 记录格式（标准模板）**

```markdown
### TC{编号}: {埋点名称}

**基本信息**:
- 事件名称: ActivityTotal
- action: {action值}
- activity_type: {类型}
- 优先级: P0/P1

---

#### 代码审查结果

**代码位置**: `acttrack/sale.go:120-145`

**字段完整性检查**:
| 字段名 | 需求 | 代码实现 | 状态 |
|--------|------|---------|------|
| activity_type | temporary_event | ✅ | ✅ |
| action | complete_task | ✅ | ✅ |
| act_id | NUMBER | ✅ actId | ✅ |
| task_id | NUMBER | ✅ taskId | ✅ |

**发现问题**:
- ✅ 无问题
或
- ❌ reward_num 硬编码为 2026（行123）
- ❌ num 字段缺失

---

#### 实际测试结果

**测试步骤**:
1. ✅ 加入测试家族（family_id=12345）
2. ✅ 消耗10000金币
3. ✅ 任务完成，触发埋点

**抓包结果**:
```json
{
  "event": "ActivityTotal",
  "properties": {
    "action": "complete_task",
    "act_id": 6360,
    "task_id": 1,
    "task_name": "累消任务",
    "stage": 1,
    "family_id": 12345
  },
  "distinct_id": "100001"
}
```

**数数平台验证**:
```sql
SELECT * FROM ActivityTotal
WHERE act_id = 6360 AND action = 'complete_task'
ORDER BY time DESC LIMIT 1;
```
- ✅ 查询到数据（延迟3分钟）
- ✅ 字段值正确
- ✅ 上报次数：1次

---

#### 多场景测试（如适用）

| 场景 | 测试内容 | 结果 |
|-----|---------|------|
| 边界场景 | 任务刚完成（进度100%） | ✅ 通过 |
| 异常场景 | 任务未完成（进度50%） | ✅ 未上报（符合预期） |

---

#### 测试结论

**状态**: ✅ 通过 / ❌ 失败

**问题清单**（如有）:
1. 🔴 **Critical**: reward_num 硬编码为2026
2. 🔴 **Critical**: num 字段缺失

**修复建议**:
- 修改 acttrack/sale.go:123，使用参数 rewardNum
- 添加 num 字段，值为奖励金币价值

---
```

**6.2 截图和证据**

为关键步骤保存截图：
- [ ] 抓包截图（显示完整JSON）
- [ ] 数数平台查询截图
- [ ] 代码截图（如发现Bug）

---

## 第七步：按照模板输出测试执行报告

完成所有测试后，按照标准模板输出测试报告。

详见：[04-report-template.md](04-report-template.md)

---

[← 返回主文档](../SKILL.md)
