itsfrank/frktest
A basic test framework for Lune
frktest
A basic unit test framework for lune. I developed this mostly for myself, if the project garners interest I will consider renaming it. Otherwise, I plan to use it for my projects until the community consolidates around an alternative (like jest-lua when it gets ported to lune)
Features
- It runs tests
- Pretty ergonomic to write (I think so)
- Assertion library, including table & array checks with diff printing, should_error, and a few more!
- Builtin console reporter with colors
- (undocumented) api to implement custom reporters (see lune_console_reporter.luau for sample use)
What does it look like tho?
Here's what a test looks like:
return function()
test.suite("A collection of tests", function()
test.case("A test that passes", function()
local exp = 4
local got = 2 + 2
check.equal(got, exp)
end)
test.case("A test that fails", function()
local exp = 3
local got = 2 + 2
check.equal(got, exp)
end)
test.case("Halt early", function()
local a = nil
req.not_nil(a)
check.falsy(a.b) -- wont run, a failed req stops the test early
end)
test.case("Custom messages!", function()
check.equal(1, 2, msg("my message prints in addition to the expansion"))
end)
test.case("Array assertions", function()
local a = { "a", "b", "c" }
local b = { "a", "z" }
check.array.contains(a, { "z", "x" })
check.array.equal(a, b)
end)
test.case("Table assertions", function()
local a = { a = 1, b = 2, c = { a = 1, b = 2 } }
local b = { a = 1, b = 22, c = { a = -1 } }
check.table.contains(a, "b")
check.table.equal(a, b)
end)
end)
end
And here is the output (theme is Rose Pine):
How do I use it
Set up your environment
Installing
frktest is available on wally, pesde, or you can just clone the repo.
using wally
Add the dependency:
in wally.toml
:
[dev-dependencies]
frktest = "itsfrank/[email protected]"
Create alias in .luaurc
:
{
"aliases": {
"frktest": "DevPackages/_Index/[email protected]/frktest/src",
}
}
using pesde
in pesde.toml
:
[dev_dependencies]
frktest = { name = "itsfrank/frktest", version = "^0.0.1" }
Create alias in .luaurc
:
{
"aliases": {
"frktest": "lune_packages/.pesde/itsfrank+frktest/0.0.1/frktest/src/"
}
}
Note: If you want to use the generated luau file in ./lune_packages
, in
the examples, replace require("@frktest/frktest")
with
require("./lune_packages/frktest")
. Reporters will be avilable in the
_reporters
member:
-- from project root
local frktest = require("./lune_packages/frktest")
local lune_console_reporter = frktest._reporters.lune_console_reporter
clone the repo
# somewhere on your machine
git clone https://github.com/itsfrank/frktest.git
Create alias in .luaurc
:
{
"aliases": {
"frktest": "<path to frktest/src>",
}
}
All example assume you created a require
alias "@frktest"
in your project's .luaurc
:
{
"aliases": {
"frktest": "<see install sections above for paths>",
}
}
note: you should also register the alias with your lsp of choice, with luau-lsp
using VSCode I think it would look like this:
"luau-lsp.require.mode": "relativeToFile",
"luau-lsp.require.directoryAliases": {
"@frktest/": "<alias in luaurc>"
}
Running tests
The framework does not have a cli or test discovery. So you need to make an entrypoint file, see examples/_run.luau for how I made mine. But basically all you need is this:
-- filename: _run.luau
-- require test files and call the returned function
require("./some_test")()
-- initialize a reporter (there is currently only one... this one, but you can make your own!)
local lune_console_reporter = require("@frktest/reporters/lune_console_reporter")
lune_console_reporter.init()
-- run the tests
local frktest = require("@frktest/frktest")
frktest.run()
Then you can run this file with lune like so:
> lune run _run.luau
Writing tests
I suggest you use these requires (but you do what you want!):
local frktest = require("@frktest/frktest")
local test = frktest.test
local check = frktest.assert.check
local req = frktest.assert.require
A test file should return a function, and for any tests to run the function
needs to create tests with test.case
. If you want to group tests together you
can use test.suite
and create tests inside of that. See examples
for how I wrote a bunch of test files.
return function()
test.case("a global test", function()
-- ...
end)
test.suite("a group of tests", function()
test.case("a test within a suite", function()
-- ...
end)
end)
end
Assertions
Every single assertion has at least one example in the examples folder. If there are any nuances, I added comments.
Really though, they should be self explanatory, your LSP should list them all
out if you type assert.check.|
End stuff
TODO
- Write tests to test the framework (ironic...)
- Encapsulate test state so that I can test the framework using the framework (with 2 separate states, one doing the testing, and one being tested)
- Probably add more assertions
- Fix bugs people might report
Acknowledgements
- martinfelis/luatablediff for a great table diff inplementation that I adapted for the
table.equal
assertions - kikito/inspect because it's the best pretty printer and I use it to print tables
- catch2 inspired the test output and probably the assertion syntax
What's up with the name?
My name is Frank, I often use frk
as a namespace/prefix for stuff meant for me :)