SuperAPI AI 工具集

moonbit-extract-spec-test

测试与质量

查看项目

更新于 10-15 14:34

技能介绍

用途

MoonBit Extract Spec & Test 用于从已有的 MoonBit 实现中反向工程出正式的 API 契约(<pkg>_spec.mbt)以及完整的测试套件,从而为已经写好的代码引入规范驱动的测试流程。

适用场景包括:

  • 用户要求“从已有实现中提取规范”
  • 用户希望“为某个包生成规范驱动的测试”
  • 用户要求“从代码创建正式 API 规范”
  • 将遗留代码转换为规范驱动开发工作流
  • 需要为现有公开 API 表面编写文档并进行测试

主要能力

1. 分析已有实现

识别公开 API 表面:

  • 列出所有 pub 和 pub(all) 类型、函数、trait
  • 记录错误类型(suberrors)及其变体
  • 记录方法签名与 trait 实现
  • 识别关键入口点与核心功能

检查测试模式(如果已有测试):

  • 查找现有测试文件(_test.mbt、_wbtest.mbt)
  • 识别测试覆盖缺口
  • 记录常见测试场景

2. 生成规范文件(<pkg>_spec.mbt)

创建正式 API 契约:

  • 对所有公开函数/类型使用 declare 关键字
  • 保留实现中的精确类型签名
  • 包含错误类型,并使用 derive(Show, Eq, ToJson) 以便测试
  • 从原始代码中添加文档注释
  • 使用 declare 的声明没有函数体
  • 对需要在测试中构造的类型使用 pub(all)
  • 对不透明类型保留 pub

规范结构示例:

///|
/// Error type for parsing operations
pub(all) suberror ParseError {
  InvalidFormat(String)
  UnexpectedEof
} derive(Show, Eq, ToJson)

///|
/// Main data type
declare pub(all) type Toml

///|
/// Convert to test JSON format
declare pub fn Toml::to_test_json(self : Toml) -> Json

///|
/// Parse TOML from string
declare pub fn parse(input : StringView) -> Result[Toml, ParseError]

3. 提取并组织测试用例

按有效性对测试分类(正常路径与错误路径):

有效测试(<pkg>_valid_test.mbt):

  • 正常路径:能触发核心功能的有效输入
  • 边界情况:边界大小、空输入、最大嵌套
  • 兼容性:与真实数据或主流实现一致的行为
  • 回归:此前修复的 bug 或已知陷阱

无效测试(<pkg>_invalid_test.mbt):

  • 错误路径:无效输入及要求的错误行为
  • 歧义:规范允许多种解释的输入(测试固定所选解释)
  • 畸形输入:语法错误、类型不匹配、约束违反

4. 编写规范驱动测试

有效输入测试示例:

///|
test "valid/category/test-name" {
  let toml_text =
    #|key = "value"
    #|
  let toml = match @pkg.parse(toml_text) {
    Ok(toml) => toml
    Err(error) => fail("Failed to parse: " + error.to_string())
  }
  json_inspect(toml.to_test_json(), content={
    "key": { "type": "string", "value": "value" }
  })
}

无效输入测试示例:

///|
test "invalid/category/test-name" {
  let toml_text =
    #|invalid syntax here
    #|
  match @pkg.parse(toml_text) {
    Ok(toml) => {
      let json = toml.to_test_json()
      fail("Expected parse to fail, got \{json.stringify(indent=2)}")
    }
    Err(_) => ()
  }
}

5. 验证

对规范进行类型检查:

moon check

运行测试:

moon test          # Run all tests
moon test -u       # Update snapshot tests

验证覆盖率:

  • 确保所有公开 API 函数都有测试
  • 检查未测试的错误路径
  • 确认边界情况已覆盖

使用方式与关键原则

规范文件规则

  • 仅声明存根:所有公开 API 使用 declare 关键字(无需函数体)
  • 精确签名:与实现的类型签名完全一致
  • 错误处理:包含所有错误类型及正确的 derive
  • 文档:保留或添加文档注释以提升清晰度
  • 测试辅助:包含 to_test_json() 之类的转换函数以便检查

测试组织

  • 黑盒测试:测试仅使用公开 API(通过 @pkg.function 调用)
  • 快照测试:对复杂值优先使用 json_inspect()
  • 清晰命名:使用描述性测试名,如 "valid/arrays/nested" 或 "invalid/keys/empty"
  • 分类:按有效性组织(<pkg>_valid_test.mbt 为正常路径,<pkg>_invalid_test.mbt 为错误路径)
  • 块分隔:使用 ///| 分隔测试块

测试覆盖目标

  • 正向用例:有效输入产生预期输出
  • 负向用例:无效输入产生适当错误
  • 边界情况:边界、空输入、特殊值
  • 集成:功能协同工作
  • 目标为 80-90% API 覆盖率

提取示例

从实现:

pub type Config

pub fn Config::parse(text : String) -> Result[Config, String] {
  // implementation
}

pub fn Config::get_value(self : Config, key : String) -> String? {
  // implementation
}

到规范:

///|
declare pub type Config

///|
declare pub fn Config::parse(text : String) -> Result[Config, String]

///|
declare pub fn Config::get_value(self : Config, key : String) -> String?

到测试:

///|
test "parse valid config" {
  let result = try? Config::parse("key=value")
  match result {
    Ok(cfg) => {
      inspect(cfg.get_value("key"), content="Some(\"value\")")
    }
    Err(e) => fail("Parse failed: \{e}")
  }
}

///|
test "parse invalid config returns error" {
  let result = try? Config::parse("invalid")
  match result {
    Ok(_) => fail("Should have failed to parse")
    Err(_) => ()
  }
}

提示

  • 从简单开始:先处理核心功能,再逐步增加复杂度
  • 利用现有测试:如果已有测试,迁移并增强它们
  • 迭代:频繁运行 moon check 以尽早发现类型错误
  • 更新快照:输出格式变化时使用 moon test -u
  • 记录推理:为非显而易见的测试用例添加注释

常见模式

使用 Result 类型测试:

let result : Result[T, Error] = try? function_call(...)
match result {
  Ok(value) => inspect(value, content="...")
  Err(e) => fail("Unexpected error: \{e}")
}

测试预期失败:

match try? function_call(...) {
  Ok(v) => fail("Expected error, got \{v}")
  Err(_) => ()  // Success - error was expected
}

使用测试 JSON 格式:

json_inspect(value.to_test_json(), content={
  "field": { "type": "integer", "value": "42" }
})

限制

资料中未提供关于收费、价格、平台支持范围或具体效果保证的信息。该技能面向 MoonBit 语言项目,依赖 moon 工具链(moon check、moon test)。