s-test
Write and run unit tests for WoW addons using Busted and the Mechanic test framework. Covers test structure, mocking WoW APIs, and coverage analysis. Use when adding tests, fixing bugs with regression
SKILL.md.claude/skills/s-test
GitHubTesting WoW Addons
Tests prove logic offline; they do not prove in-game behaviour. For that, use the reload protocol in using-mechanic.
Related Commands
MCP Tools
| Task | MCP Tool |
|---|---|
| Fast offline Core tests | sandbox.test(addon="MyAddon", filter="optional name pattern") |
| Busted tests, full addon environment | addon.test(addon="MyAddon"), addon.test(addon="MyAddon", coverage=true) |
| Run a snippet in the sandbox | sandbox.exec(code="return 1 + 1", addon="MyAddon") |
| Regenerate WoW API stubs | sandbox.generate(namespace="C_Spell") or all (force=true to rebuild); sandbox.status reports them |
All four run Lua on your machine, so they are flagged mutating (code execution). Only run them on code you are working on.
sandbox.test layout and behaviour
- The addon is looked up in the
_dev_folder. Source files are the top-levelCore/*.luafiles (init.luafirst, then alphabetical; subfolders are not auto-loaded because they need ordered dependencies, so useaddon.testfor those). - Specs are
*_spec.luafiles inCore/or underTests/(capitalT). With none, the result isNO_TEST_FOLDERSor an empty run. - A packaged mini framework is used, so nothing has to be generated first; WoW API stubs from
sandbox.generateare loaded too when they exist. It provides:describe,it,before_each,after_each,setup,teardownandassert.equals / not_equals / is_true / is_false / truthy / falsy / is_nil / is_not_nil / is_near / match / has_error / same. - Code runs in a restricted environment: whitelisted globals only; no
os,io,package,debug,dofile,loadfile,load,getfenv/setfenv,string.dump.requireworks in specs but only for modules beneath the addon folder. 30s/60s timeouts, 256 KB output cap, memory is not limited. filterruns only tests whose full name contains the text (case-insensitive). The result listspassed_count,failed_count,tests(failures first),source_files,spec_filesandduration_ms; runner problems come back as structured errors (LUA_FAILED,LUA_NOT_FOUND,FRAMEWORK_MISSING,NO_TEST_SUMMARY,TIMEOUT). Read them instead of re-running blindly.
-- Core/Math_spec.lua
describe("Core math", function()
it("clamps", function()
assert.equals(10, Core.Clamp(15, 0, 10))
end)
end)
addon.test (Busted)
Runs the system/desktop/bin busted over *_spec.lua files; with a .busted file in the addon its ROOT is respected, otherwise Tests/, tests/ or spec/ are used. The result reports totals, per-test errors and busted errors. Needs the Lua toolchain (tools.status). coverage=true adds a coverage report.
Routing Logic
| Request type | Load reference |
|---|---|
| Sandbox, Busted, in-game guides | ../../../docs/integration/testing.md |
| Busted spec patterns | references/busted-patterns.md |
| Mocking WoW APIs | references/wow-mocking.md |
| MechanicLib test registration | ../k-mechanic/references/mechaniclib.md |
Recommended workflow
- Sandbox (Core) for fast feedback on pure logic; write a failing regression test first when fixing a bug.
- Busted for module interactions and anything needing the full TOC load order.
- In game for the final check against live APIs, through MechanicLib-registered tests and
addon.outputafter a confirmed reload. - Keep logic in the Core layer; tests that need many WoW mocks usually mean logic leaked into the view layer.