来源说明:本文参考 Uberi 的 Yunit 项目和官方文档整理。Yunit 是一个面向 AutoHotkey 的轻量测试框架,可用于自动化代码测试、基准测试、结果输出和测试管理。本文结合本站 AI 写的 AHK 代码怎么验收,讲它在 AHKv1 脚本里的实际用法。

很多 AHK 脚本平时靠“运行一下看起来没报错”来验收。小脚本问题不大,但一旦开始写函数库、自动办公、网络请求、字符串处理、路径处理,靠肉眼点几下就不够了。Yunit 的价值是:把你认为必须成立的结果写成测试,让脚本自己帮你反复检查。

一、Yunit 适合测什么

Yunit 最适合测试纯逻辑和可重复结果,例如:

  • 字符串处理函数。
  • 路径拼接函数。
  • JSON/CSV 数据转换。
  • 时间、数字、数组、对象处理。
  • AI 生成的工具函数是否符合预期。

它不太适合直接测试“鼠标有没有点到某个窗口”“某个按钮颜色是否变化”这种强依赖外部环境的内容。GUI 和窗口自动化也能测,但要做更多准备,初学者先从函数测试开始。

二、最小测试结构

Yunit 的基本用法是:引入 Yunit,选择输出模块,然后把测试类交给 Test()。测试类里的方法就是测试项;正常结束就是通过,抛出异常就是失败。最常用的是 Yunit.Assert()

#Requires AutoHotkey v1.1
#NoEnv
#SingleInstance Force

#Include %A_ScriptDir%\Lib\Yunit\Yunit.ahk
#Include %A_ScriptDir%\Lib\Yunit\Window.ahk

Yunit.Use(YunitWindow).Test(TestString)
return

class TestString
{
    TrimText()
    {
        result := Trim("  AHK  ")
        Yunit.Assert(result = "AHK", "Trim 后应该得到 AHK")
    }

    SplitCount()
    {
        arr := StrSplit("a,b,c", ",")
        Yunit.Assert(arr.Length() = 3, "应该拆出 3 个元素")
    }
}

官方文档里提到,测试方法不需要参数,也不需要返回值。只要测试方法正常跑完,就算通过;如果 Assert 失败,会抛出异常并记录失败信息。

三、目录怎么放

Yunit 文档建议把 Yunit 文件夹放进项目的库路径里。AHKv1 常见库搜索顺序包括脚本目录下的 Lib、用户文档目录下的 Lib、以及 AutoHotkey 安装目录下的 Lib

SomeProject
|-- Lib
|   |-- Yunit
|   |   |-- Yunit.ahk
|   |   |-- Window.ahk
|   |   |-- Stdout.ahk
|   |   |-- OutputDebug.ahk
|   |   |-- JUnit.ahk
|-- MyLib.ahk
|-- MyLib_Test.ahk

如果你只是自己用,放在当前项目 Lib 里最清楚,不容易和别的项目版本冲突。

四、输出模块怎么选

Yunit 有多个输出模块。新手建议先用 YunitWindow,因为它会用窗口显示测试结果,最直观。

  • YunitWindow:窗口显示结果,适合本机手动运行。
  • YunitStdout:输出到标准输出,适合命令行和自动化脚本。
  • YunitOutputDebug:输出到调试器,适合配合 DebugView 等工具。
  • YunitJUnit:生成 JUnit XML,适合 CI 或更正式的测试流程。
; 同时使用窗口和标准输出
Yunit.Use(YunitWindow, YunitStdout).Test(TestString, TestPath)

五、测试类和分类

Yunit 用 class 组织测试。类里的方法是测试项,嵌套类可以作为分类。这样你的测试文件不会很快变成一堆散乱函数。

class TestPath
{
    JoinBasic()
    {
        path := JoinPath("C:\Test", "a.txt")
        Yunit.Assert(path = "C:\Test\a.txt", "路径拼接错误")
    }

    class FileName
    {
        Extension()
        {
            ext := GetExt("demo.ahk")
            Yunit.Assert(ext = "ahk", "扩展名应该是 ahk")
        }
    }
}

测试名称来自类名和方法名,所以建议命名清楚。不要写 Test1Test2,过一周你自己也不知道它在测什么。

六、Begin 和 End:每个测试前后准备环境

官方文档里提到,特殊方法 Begin()End() 会在每个测试前后调用。它适合准备临时变量、创建测试文件、清理环境。

class TestTempFile
{
    Begin()
    {
        this.file := A_Temp "\ahk_test.txt"
        FileDelete, % this.file
    }

    WriteRead()
    {
        FileAppend, hello, % this.file, UTF-8
        FileRead, text, % this.file
        Yunit.Assert(text = "hello", "写入后读出的内容不一致")
    }

    End()
    {
        FileDelete, % this.file
    }
}

这样测试之间互不影响。不要让一个测试依赖另一个测试先运行,因为测试调用顺序不应该成为脚本正确性的前提。

七、用 Yunit 验收 AI 写的 AHK

AI 写 AHK 最容易出现的问题是:看起来很像对,但边界条件没处理。比如路径最后有没有反斜杠、空字符串怎么办、中文编码怎么办、数组下标从 1 开始还是 0 开始。这些问题特别适合写成测试。

class TestAiFunction
{
    EmptyInput()
    {
        Yunit.Assert(NormalizeName("") = "", "空输入应该返回空")
    }

    ChineseText()
    {
        Yunit.Assert(NormalizeName("脚本 测试") = "脚本_测试", "中文空格替换失败")
    }

    KeepExtension()
    {
        Yunit.Assert(NormalizeName("demo.ahk") = "demo.ahk", "不应该破坏扩展名")
    }
}

你不需要一开始就写很多测试。最实用的做法是:每次发现一个 bug,就把它写成一个测试。这样同类问题以后不会反复回来。

八、哪些东西不适合一开始就测

不建议新手一上来就用 Yunit 测复杂 GUI、游戏窗口、剪贴板、浏览器页面、管理员权限窗口。这些场景受环境影响大,写测试会很繁琐。

更好的路线是:

  • 把核心逻辑拆成函数。
  • 先测试函数。
  • 窗口、鼠标、键盘、权限等部分用人工验收清单。
  • 重要脚本再逐步加入日志和自动检查。

站内延伸

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。