12345678Build a ball pit · Step 7 of 8
Test it
You'll learn
- Write tests with
describe,itandexpect - Run them with
pkg test - Press buttons from a test
- Time
- 15 min
- Builds on
- Step 6: Remember things
- File
ballpit/tests/pit_test.lua
So far you have tried each change to the pit by hand. In this step you write tests that try it for you: one file checks the pit's logic, and another presses the toolbar's buttons as a person would.
Test the pit
A package's tests live in its tests/ folder, in files whose names end
in _test.lua. pkg new wrote one already,
tests/01_example_test.lua, which checks that 1 + 1 is 2. A test file
loads your modules with require, as init.lua does. init.lua
itself does not run, so each test sets up what it checks.
Save this as ballpit/tests/pit_test.lua:
local pit = require("pit")
describe("pit", { before_each = pit.clear })
it("counts the balls it adds", function()
pit.add()
pit.add()
expect(pit.count()).to_be(2)
end)
it("is empty once cleared", function()
pit.add()
pit.clear()
expect(pit.count()).to_be(0)
end)
it("tells its listeners each new count", function()
local counts = {}
pit.on_change(function(n)
table.insert(counts, n)
end)
pit.add()
pit.add()
pit.clear()
expect(counts).to_equal({ 1, 2, 0 })
end)
describenames a group of tests. Eachitadds a test to the group: a name, then a function that runs the test.expecttakes a value to check..to_be(other)passes when the two are equal and fails the test when they are not.to_equalcompares tables, entry by entry.- All the test files run in one app, so
require("pit")gives every test the same pit.before_each = pit.clearempties it before each test, so no test sees the balls of the one before.
Run the package's tests with pkg test:
$ datumhue pkg test ballpit
A window opens while the tests run, and closes when they end. Each test
prints a line, ok when it passed, and the last line counts them:
1..4
# run seed: 1282112497
ok 1 - example > runs
ok 2 - pit > counts the balls it adds
ok 3 - pit > is empty once cleared
ok 4 - pit > tells its listeners each new count
# 4 passed, 0 failed, 0 skipped in 0.1s
A test that fails prints not ok, then the file and line of the check,
with the value it expected and the one it got.
Press a button from a test
A test can also use your app as a person does.
datumhue.debug.input moves the pointer, clicks and presses keys, and
your app hears them as it hears real input. Save this as
ballpit/tests/toolbar_test.lua:
local pit = require("pit")
local toolbar = require("toolbar")
local input = datumhue.debug.input
describe("toolbar", { before_each = pit.clear })
it("adds a ball on a click and on the A key", function()
local bar = toolbar.new(datumhue.ui.root)
wait_until(function()
return bar.add.bounds ~= nil
end)
local center = bar.add.bounds.center
input.cursor(center.x, center.y)
input.click()
wait_until(function()
return pit.count() == 1
end)
input.tap("a")
wait_until(function()
return pit.count() == 2
end)
expect(bar.count.text).to_be("Balls: 2")
end)
In this example: datumhue.debug.input datumhue.ui.root datumhue.debug.input.cursor datumhue.debug.input.click datumhue.debug.input.tap
- The test builds the toolbar on
datumhue.ui.root, the whole window. - A widget has no place on screen until it is laid out, in the frame
after it is made.
wait_untilwaits a frame at a time until its function returns true: here, until the Add ball button has itsUiElement.bounds.wait_frameswaits a set number of frames, for a test that needs time to pass rather than a condition to hold. debug.input.cursormoves the pointer to the button's center, in the unitsboundsuses, anddebug.input.clickclicks there.debug.input.tappresses a key and lets it go.- Your app hears the input in the next frame, as it hears real input, so the test waits for each new ball before it checks.
Run datumhue pkg test ballpit again. The last line now counts
5 passed, 0 failed.
Test a package shows how to run only some of the
tests, measure how much of your code they cover and keep a report.
Package testing lists every check expect offers.
Try this
- Make a test fail on purpose: expect 3 balls where there are 2, and read what the run prints.
- Test the Clear button: at the end of the test, click it, then check the pit's count and the counter's text.
- In a second test in
toolbar_test.lua, add three balls, then build a toolbar. Test that its counter starts atBalls: 3.
Recap
- Tests live in
tests/, in files that end in_test.lua, anddatumhue pkg testruns them. describenames a group,itadds a test, andexpectchecks a value.- Tests load your modules with
require;init.luadoes not run. datumhue.debug.inputclicks and presses keys from a test. Wait a frame before you check what it did.
New in this step