Skip to content

改进 OpenCC 测试结构:使用单一输入一次测试多个 config,以降低测试编写与 review 成本 #1003

Closed

Description

@frankslin

提案:改进 OpenCC 测试结构——单一输入一次测试多个 config

各位维护者好, 我想提出一个关于 OpenCC 测试结构的改进提案,目标是降低测试编写与 review 成本,并更直观地展示不同 config 之间的差异。

现有问题

当前测试以「每个 config 一组 input / output 文件」为单位,这在验证单个 config 时有效,但在实际维护中存在问题:

  • 同一段输入在不同 config 下的差异被分散在多个文件中
  • review 时需要同时打开多个文件对比
  • 新贡献者不清楚应该改哪些文件,测试编写门槛较高

很多实际问题并不是某个 config 是否能跑,而是不同 config 之间的输出差异是否合理。

核心想法

引入一种新的测试定义方式:

  • 以「输入文本」作为测试的基本单元
  • 在一个文件中一次性定义该输入在多个 config 下的预期输出
  • 使用 JSON 作为测试定义格式 即从「一个 config → 一个 input → 一个 output」变为「一个 input → 多个 config → 各自的 expected output」
{
  "cases": [...,
    {
      "id": "case_014",
      "input": "高剂量的苦瓜素还会抑制胚胎发育",
      "expected": {
        "s2hk": "高劑量的苦瓜素還會抑制胚胎發育",
        "s2t": "高劑量的苦瓜素還會抑制胚胎發育",
        "s2tw": "高劑量的苦瓜素還會抑制胚胎發育",
        "s2twp": "高劑量的苦瓜素還會抑制胚胎發育"
      }
    },...
  ]
}
...

这样做的好处是:

  • 一个文件即可看清所有 config 的差异
  • review 更直观,可直接讨论差异是否符合设计预期
  • 贡献者每次只需要改一个文件,明显降低测试编写成本,鼓励贡献者多写测试

关于测试切换方式

我个人更倾向于一次性采用这种「单文件、多 config」的测试模型,因为「只有一个地方需要改」能显著降低心智负担。

如果维护者认为一次性切换风险较高,也可以作为折中方案,让新结构与现有测试结构并存,仅用于需要横向对比的用例。

额外收益:可直接运行的 Bazel 测试

该方案中还新增了一个基于 Bazel 的测试入口:

  • 测试可直接以 bazel test //data/config:config_dict_validation_test 作为命令运行。
  • 贡献者可以在本地快速验证修改是否正确,而无需等待 binary 编译全部完成。

PoC

我已经做了一个 proof-of-concept 的实现,仅涉及测试结构与 runner,不修改转换逻辑本身: frankslin#9

如果这个方向被认为是可接受的,我可以再整理一个更符合 upstream 风格的完整版本提交。

感谢你们的时间和反馈。

Activity

  1. BYVoid commented on Jan 13, 2026

    @BYVoid
    Owner

    支持這個提議,這樣的結構確實一目了然。

  2. danny0838 commented on Jan 13, 2026

    @danny0838
    Contributor

    有沒有考慮改用 YAML?這比 JSON 更簡潔、更適合人工編輯,並且支援註解。

  3. frankslin commented on Jan 13, 2026

    @frankslin
    CollaboratorAuthor

    谢谢 Danny 的建议,有考虑过 YAML。只要能结构化、无歧义地表达测试用例,用哪个格式都可以。我注意到 ZhConvert 项目有公开过一个测试集就是用 YAML 表达的,已通过脚本将其转换为上述 JSON 格式来做 cross-validation。

    我最后选了 JSON,主要是出于如下考虑:

    1. 项目中已有用 JSON 之先例(config 文件);
    2. 最初的出发点是将原始的测试定义转换给 网页 内使用,在 JS 中解析 JSON 比较方便;
    3. YAML 虽易手写,但是遇到缩进等格式反而较容易出错,或导致测试定义被意外略过。JSON 配合 formatter 不大容易在这方面出错;
    4. YAML 可能会「邀请」高手使用其高级语法(如 template),这会增加解析和理解的复杂度,违背了测试配置与代码简单易读的初衷。

    至于缺少 comment 机制的问题,如果认为确有这一需要,可以增加一个或多个扩展 key 当作 comment。这些 fields 测试代码会自动忽略。我早先有尝试通过这种方式扩展 config 定义,让它集成测试用例,等等。例如: frankslin@fda9011

  4. danny0838 commented on Jan 13, 2026

    @danny0838
    Contributor

    谢谢 Danny 的建议,有考虑过 YAML。只要能结构化、无歧义地表达测试用例,用哪个格式都可以。我注意到 ZhConvert 项目有公开过一个测试集就是用 YAML 表达的,已通过脚本将其转换为上述 JSON 格式来做 cross-validation。

    我最后选了 JSON,主要是出于如下考虑:

    1. 项目中已有用 JSON 之先例(config 文件);
    
    2. 最初的出发点是将原始的测试定义转换给 [网页](https://opencc.js.org/wasm) 内使用,在 JS 中解析 JSON 比较方便;
    
    3. YAML 虽易手写,但是遇到缩进等格式反而较容易出错,或导致测试定义被意外略过。JSON 配合 formatter 不大容易在这方面出错;
    
    4. YAML 可能会「邀请」高手使用其高级语法(如 template),这会增加解析和理解的复杂度,违背了测试配置与代码简单易读的初衷。
    

    至于缺少 comment 机制的问题,如果认为确有这一需要,可以增加一个或多个扩展 key 当作 comment。这些 fields 测试代码会自动忽略。我早先有尝试通过这种方式扩展 config 定义,让它集成测试用例,等等。例如: frankslin@fda9011

    1. 我認為可以考慮反過來,即專案本身的 config 改成 YAML 格式。不過這點的確影響層面較大,要看負責人本身的想法。

    2. 這點與 OpenCC 專案本身無關。就算改成了 YAML 也是網頁版掛個 library 可以解決的事。

    3. 不太確定你指的是什麼情況,就目前看來,測試實例應該大多是單行中文字串,不太可能涉及特殊字元或多行縮排語法而造成問題;反之如果確實要使用多行文字的測試用例,YAML 的縮排語法表達多行文字的易讀性也遠勝於在 JSON 字串夾雜 \n。

      不曉得所謂 ZhConvert 的測試集是不是指這個,如果是指這個我的想法同前。

      反過來說,YAML 帶來的易寫性優勢很大,尤其測試可能常有不定個數的 expected cases,光是擴充 cases 省去增減 expected config cases 時處理尾逗點的麻煩就差很多了。

    4. 這個應該是專案本身規範不要使用進階語法,或只限縮在明顯能增加可讀性的情況即可。

    不過我同意 JSON 和 YAML 的確各有優缺點,也沒有一定要堅持 YAML,看專案主本身的想法吧。

  5. danny0838 commented on Jan 13, 2026

    @danny0838
    Contributor

    另外,提案是用項目陣列且每項皆有 "id" 屬性,我不曉得測試用例加上 id 的必要性為何,會傾向 "id" 屬性改為可選甚至改成更靈活的 "name" 或 "description"。

    反之,如果 id 是必要的,那似乎改成用 JSON 物件表達更好:

    {
      "cases": {
        "case_014": {
          "input": "高剂量的苦瓜素还会抑制胚胎发育",
          "expected": {
            "s2hk": "高劑量的苦瓜素還會抑制胚胎發育",
            "s2t": "高劑量的苦瓜素還會抑制胚胎發育",
            "s2tw": "高劑量的苦瓜素還會抑制胚胎發育",
            "s2twp": "高劑量的苦瓜素還會抑制胚胎發育"
          }
        },
        ...
      }
    }
    ...
    
  6. frankslin commented on Jan 13, 2026

    @frankslin
    CollaboratorAuthor

    关于上面提供的例子,转换成 YAML 的等价形式如下,在 bazel 体系内可以用 BUILD rule 转换成 JSON (反过来也行)实现双重语法的支持。

    cases:
      - id: case_014
        input: 高剂量的苦瓜素还会抑制胚胎发育
        expected:
          s2hk: 高劑量的苦瓜素還會抑制胚胎發育
          s2t: 高劑量的苦瓜素還會抑制胚胎發育
          s2tw: 高劑量的苦瓜素還會抑制胚胎發育
          s2twp: 高劑量的苦瓜素還會抑制胚胎發育

    关于前面说的「YAML 缩进格式容易出错」意思是,因为缩进层级较为复杂,而且一旦写得不对,就可能出现 silently ignored 的问题。YAML parser 通常对输入比较宽松;我曾遇到过此类情况,写了测试案例以为测到了,实际没被运行。这种问题很难发现,但可以通过额外加 schema validation 来解决,只是需要额外工作。

    目前我的测试代码中对 id 的处理是可选的,如果提供了 id,在测试失败时候可输出,方便定位和 debug。带编号的 ID 是写脚本将原始 test cases 顺序生成的,没有特别的考量。一次性 migration 成新格式后,今后再加的新测试 id 可以随意写。例如这样: https://github.com/frankslin/OpenCC/blob/1d0df87e5537f6d72c6653bede86cbc763d3005e/test/testcases/testcases.json#L372

  7. frankslin commented on Jan 13, 2026

    @frankslin
    CollaboratorAuthor

    已完成 #1006

  8. BYVoid commented on Jan 14, 2026

    @BYVoid
    Owner

    我支持JSON,Yaml帶來的好處不算太多但是會增加各個語言的依賴,即便僅僅是測試。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions