报告:补 P2 批次(覆盖率口径与关键页冒烟)记录
This commit is contained in:
@@ -1076,3 +1076,107 @@ go test -count=1 -v ./...
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 修复记录(第十二批 · P2:覆盖率口径与关键页冒烟)
|
||||||
|
|
||||||
|
## 一、先纠正一个测量错误:`rond` 不是 38.8%
|
||||||
|
|
||||||
|
看到「`rond` 只有 38.8%」本来准备补测试,取证后发现**数字是量错了**:
|
||||||
|
|
||||||
|
`go test -cover` 只统计**测试文件所在那个包**自己的执行。而 `internal/rond` 一半的代码
|
||||||
|
(`export.go` 1416 行)由 `internal/web` 的 `TestMovementCleanExport` 驱动;`geo`/`gpx`/
|
||||||
|
`notes`/`votes` 同理由 `web`/`stats` 驱动。按 `-cover` 量,这些包一律报 0%。
|
||||||
|
|
||||||
|
| 包 | `-cover`(假口径) | `-coverpkg=./internal/...`(真) |
|
||||||
|
|---|---|---|
|
||||||
|
| `internal/rond` | 38.8% | **82.2%** |
|
||||||
|
| `internal/geo` | 0% | **92.9%** |
|
||||||
|
| `internal/stats` | 62.2% | **83.7%** |
|
||||||
|
| `internal/web` | 53.2% | 53.2%(它自己不假) |
|
||||||
|
|
||||||
|
⇒ `verify.sh --cover` 改用 `-coverpkg=./internal/...`,并按包打印。**项目合计 62.3%**。
|
||||||
|
|
||||||
|
解析 profile 时有个坑:`-coverpkg` 下每个测试二进制都会给同一段代码写一条记录,
|
||||||
|
同一个 `(文件,行段)` 会出现多条(一条 `count=0`、一条 `count>0`)。**必须按块取 max**;
|
||||||
|
直接求和等于把语句数乘上二进制份数,每包都会显示成只有 `1/N`(第一版 awk 就这么错的,
|
||||||
|
`web` 印成 4.4%)。
|
||||||
|
|
||||||
|
## 二、真去补的时候,只补「线上会走到」的
|
||||||
|
|
||||||
|
把未覆盖行段拉出来逐条看,绝大部分是 `nil` 分支和 `if err != nil { return err }`——补那些是灌水。
|
||||||
|
真正「线上会走到、却一条用例都没有」的只有两处:
|
||||||
|
|
||||||
|
**① `BuildMergePlan` 的地点/活动冲突**(`placePick`/`activityPick` 长期 0%)。差异页线上确实会提交
|
||||||
|
这两类选择,而用例只造过「新增」。补 `merge_clash_test.go`(冲突 + 删除逐条勾选)后
|
||||||
|
`merge.go` 64.3% → **96.4%**。
|
||||||
|
变异验证:把地点判据从 `PickBackup` 改成 `PickDB` ⇒ 红在「只有选了『用实机』的地点该更新」;
|
||||||
|
把活动键从 `activityKey(cf.DB)` 改成 `cf.DB.Name` ⇒ 红在「有 UUID 的活动应按 UUID 对上」。
|
||||||
|
|
||||||
|
**② `internal/gpx` 整包零测试**(61 条语句,0/61)。它解析的是**用户上传的 XML**,
|
||||||
|
正是最该有测试的地方。补 `gpx_test.go` 8 条:`trk`/`rte` 两条分支、track 名退回 `metadata>name`、
|
||||||
|
`(0,0)` 空点丢弃、单点轨迹丢弃并报错、非法 XML、没有轨迹点、时间格式错不致命、里程数值。
|
||||||
|
⇒ **0% → 96.0%**。
|
||||||
|
变异验证:`(0,0)` 跳过改成 `if false` ⇒ 红在「该被丢掉,实际剩 3 个点」;
|
||||||
|
地球半径 6371→6300 ⇒ 红在「1 度纬度该约 111.19 km」。
|
||||||
|
|
||||||
|
## 三、顺手清掉两处死代码
|
||||||
|
|
||||||
|
两者都做过全仓核查(含模板——Go 模板能调方法,`{{.Total}}` 这种不能只搜 `.go`):
|
||||||
|
|
||||||
|
| 死代码 | 核查结果 |
|
||||||
|
|---|---|
|
||||||
|
| `rond.Counts.Total()` | 零引用。模板里的 `.Total` 都是各页 view 结构体自己的字段。 |
|
||||||
|
| `gpx.Track.BBox()` | 零引用。`handlers_topics.go` 里的 `fitBBox` 是无关变量,`gpx.Track` 从未传进模板。 |
|
||||||
|
|
||||||
|
**没有为它们写测试**——为了把 0% 填成 100% 而给死代码补用例,只会把死代码固化下来。
|
||||||
|
|
||||||
|
## 四、一条「实测否证」的记录
|
||||||
|
|
||||||
|
`geo.Haversine` 用 `math.Asin(math.Min(1, math.Sqrt(a)))` 夹了一道,`gpx` 那份没有,
|
||||||
|
SQL 里(`handlers_topics.go`)也没有。三条公式、两个半径(6371.0 / 6371.0088)。
|
||||||
|
|
||||||
|
本来准备按「缺夹子会出 NaN」去修,**实测不成立**:对跖点附近 `h` 最多到 `1+2^-52`
|
||||||
|
((45,0)→(-45,180) 就是这个值),而 `math.Sqrt(1+2^-52)` 会回舍成正好 `1.0`,
|
||||||
|
`asin(1.0)=π/2`,出不了 NaN。所以**没改代码**,只留一条 `TestLengthKmAntipodalIsFinite`
|
||||||
|
把「对跖点不出 NaN」钉住(将来换公式或去掉开方会立刻红),并在注释里写明这是实测结论。
|
||||||
|
|
||||||
|
半径差 6371.0 vs 6371.0088 的数值影响:146 km 上差 **0.20 米**,纯属口径不统一,不影响功能。
|
||||||
|
|
||||||
|
## 五、关键页冒烟:`scripts/smoke.py`
|
||||||
|
|
||||||
|
Go 侧模板守卫只能证明「模板里有那段文字」。白屏、JS 抛错、内容区块被压成 0 高,
|
||||||
|
**模板测试全是绿的**。冒烟按三种口径各走一遍(16 页):
|
||||||
|
|
||||||
|
1. **站长(浏览器)**:HTTP 200 + 落点路径没跳走 + 内容区块在且尺寸非 0 + 零 JS 报错
|
||||||
|
2. **访客(纯 HTTP)**:公开页 200;后台页必须 **303 跳登录**(绝不能 200)——`urllib` 不跟随跳转即可,
|
||||||
|
比开 Chrome 快一个数量级
|
||||||
|
3. **访客(浏览器)抽检** `/` 与地点详情:只在访客侧复现的 bug 藏在这里
|
||||||
|
|
||||||
|
接进 `verify.sh --smoke`(只跑冒烟)/ `--all`(全量 + 冒烟)。
|
||||||
|
|
||||||
|
三条实测踩出来的坑:
|
||||||
|
|
||||||
|
- **关键区块不能取 `nav.nav`**:它在 `layout.html` 里,内容块整个没渲染它照样在,等于没断言。
|
||||||
|
改成地图页取地图容器、其余取首个 `.card`(`#home-map` / `#map` / `#place-map` / `#taxonomy`)。
|
||||||
|
- **用 `.card` 而不是 `div.card`**:专题列表的卡片是 `<a class="card topic-card">`,
|
||||||
|
写 `div.card` 一个都选不中——而 `querySelector` 返回 null 时尺寸也是 0,打印出来跟
|
||||||
|
「元素被压成 0 宽」一模一样。第一版就据此差点去查布局 bug。日志已把两者分开印。
|
||||||
|
- **`--min-body` 只是兜「整页空白」**:专题列表正文天生 166 字(就一个专题卡片),阈值定 200 会假红。
|
||||||
|
另外「公开页面」是受总开关控制的,冒烟先探测 `/places` 的访客状态码再决定同类页的期望值。
|
||||||
|
|
||||||
|
**变异验证**:往 `timeline.html` 塞一句 `<script>throw new Error('smoke-mutation-probe')</script>`
|
||||||
|
(`debug=true` 下模板热加载,不用重启)⇒ 冒烟立刻红在「JS 报错」上,且**状态码、内容区尺寸全都正常**
|
||||||
|
——正好说明没有这条断言就会放过它。验完已还原(`git status` 无该文件)。
|
||||||
|
|
||||||
|
## 六、收尾验收
|
||||||
|
|
||||||
|
```
|
||||||
|
./scripts/verify.sh # 284 个顶层用例(含子测试更多)/ 0 FAIL / 0 SKIP
|
||||||
|
./scripts/verify.sh --all # 全量 + 冒烟 16 页全绿
|
||||||
|
./scripts/verify.sh --cover # 按包覆盖率 + 项目合计 62.3%
|
||||||
|
./scripts/verify.sh --fast # gofmt / vet / build 干净
|
||||||
|
```
|
||||||
|
|
||||||
|
`--fast` / `--smoke` / `--cover` / `--all` / 未知参数 → exit 2 的门都实测过。
|
||||||
|
|||||||
Reference in New Issue
Block a user