mcpField
T
test-namer

test-namer

github.com/mryll测试与质量638 次安装2 周前更新
代码仓库

关于 test-namer

面向开发者的测试技能,指导使用通俗英语描述可观察行为,而非实现细节。它提供针对不同语言的命名建议,并强调以行为为中心的测试。

主要功能

  1. 01用通俗英语描述行为
  2. 02避免僵化命名模板
  3. 03适配各语言命名惯例
  4. 04优先测试可观察行为
  5. 05选择合适的测试风格

适用场景

  1. 01为领域行为测试命名
  2. 02编写 Go 或 Python 测试
  3. 03命名 JavaScript 测试用例
  4. 04检查耦合实现细节的测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mryll/skills --skill test-namer

安装后在 Claude Code 中输入/test-namer确认已加载。

附带文件references/anti-patterns.mdreferences/testing-philosophy.md

详细介绍

Test Namer

编写用通俗英语描述行为而非实现细节的测试。基于 Vladimir Khorikov 的测试原则。

命名指南

规则
  1. 不要采用死板的命名策略——切勿使用 [MethodUnderTest]_[Scenario]_[ExpectedResult] 或类似模板
  2. 向熟悉问题领域的非程序员描述行为——领域专家应该能理解测试名称
  3. 在函数/方法名称中用下划线分隔单词(基于字符串的测试名称,例如 JS/TS 中则不需要)
  4. 不要在测试名称中包含 SUT 的方法名称——测试行为,而不是方法
  5. 陈述基本事实,而非愿望——写 is_invalid,不要写 should_be_invalid
  6. 使用基本英语语法——冠词(a、the)能提升可读性
  7. 明确具体——Delivery_with_a_past_date_is_invalid 比 Delivery_with_invalid_date_is_invalid 更好
命名改进示例

从死板的约定开始,逐步改进:

IsDeliveryValid_InvalidDate_ReturnsFalse     -- rigid, cryptic
Delivery_with_invalid_date_should_be_invalid  -- plain English (good start)
Delivery_with_past_date_should_be_invalid     -- more specific
Delivery_with_past_date_is_invalid            -- fact, not wish
Delivery_with_a_past_date_is_invalid          -- natural grammar (final)
例外:工具代码

对于没有业务逻辑的工具/辅助代码,可以引用方法名称,因为其行为对业务人员没有意义:

Sum_of_two_numbers
Trimmed_string_has_no_leading_whitespace

特定语言的调整

Go

测试函数必须以 Test 开头(语言要求)。后接描述性名称:

func TestDelivery_with_a_past_date_is_invalid(t *testing.T) { ... }

通过 t.Run 编写的子测试,命名不受限制:

func TestDelivery(t *testing.T) {
    t.Run("with a past date is invalid", func(t *testing.T) { ... })
    t.Run("with a future date is valid", func(t *testing.T) { ... })
}

表驱动测试——使用描述性的 name 字段,而不是方法签名:

tests := []struct {
    name string
    // ...
}{
    {"delivery with a past date is invalid", ...},
    {"delivery for tomorrow is valid", ...},
}
Python (pytest)

函数必须以 test_ 开头。后接 snake_case 格式的描述性名称:

def test_delivery_with_a_past_date_is_invalid():
    ...

def test_new_customer_starts_in_pending_state():
    ...
Java / Kotlin (JUnit)

@Test 注解负责测试发现。方法名称可以完全自由地描述:

@Test
void Delivery_with_a_past_date_is_invalid() { ... }

@Test
void New_customer_starts_in_pending_state() { ... }

Kotlin 支持使用反引号括起自然语言名称:

@Test
fun `delivery with a past date is invalid`() { ... }
JavaScript / TypeScript (Jest, Vitest, Mocha)

基于字符串的名称——直接使用自然语言,无需下划线:

it("delivery with a past date is invalid", () => { ... });

test("new customer starts in pending state", () => { ... });

describe("delivery validation", () => {
    it("rejects past dates", () => { ... });
    it("accepts future dates", () => { ... });
});
C# / .NET

使用 [Fact] 或 [Test] 属性。下划线用法不受限制:

[Fact]
public void Delivery_with_a_past_date_is_invalid() { ... }
Rust

使用 #[test] 属性。采用标准的 snake_case 标识符:

#[test]
fn delivery_with_a_past_date_is_invalid() { ... }

测试类/文件命名

使用 [ClassName]Tests 或 [feature]_test 作为入口点,而非边界。单元测试中的单元指一个行为单元,而非一个类——它可以跨越多个类。

测试什么——行为,而非实现

  • 测试可观察的行为:输出、状态变化、客户端可见的副作用
  • 绝不测试实现细节:内部协作、私有方法、精确的 SQL 查询、特定的方法调用顺序
  • 重命名内部方法绝不应该导致测试失败
  • 如果测试在合理重构期间失败,说明测试与实现耦合

测试风格(按优先顺序)

  1. 基于输出——输入数据,验证输出。最能抵御误报。适用于纯函数和领域逻辑。
  2. 基于状态——执行操作,通过公共 API 验证最终状态。无法验证输出时很有用。
  3. 基于通信(模拟)——验证与依赖项的交互。仅用于不受控的外部依赖(SMTP、消息总线、第三方 API)。绝不模拟领域对象或稳定的依赖项。

有关测试风格、价值主张和务实测试策略的深入指南,请参阅 testing-philosophy.md。

有关应避免的常见反模式,请参阅 anti-patterns.md。

评论

支持 Markdown