Unit Testing: Finish chapter

master
rubenwardy 2018-07-15 19:02:10 +01:00
parent bc58dce630
commit ca0db29ba0
No known key found for this signature in database
GPG Key ID: A1E29D52FF81513C
2 changed files with 171 additions and 20 deletions

View File

@ -18,7 +18,7 @@ editor to provide alerts to any mistakes.
* [Running LuaCheck](#running-luacheck)
* [Configuring LuaCheck](#configuring-luacheck)
* [Troubleshooting](#troubleshooting)
* [Checking commits with Travis](#checking-commits-with-travis)
* [Checking Commits with Travis](#checking-commits-with-travis)
## Installing LuaCheck
@ -103,7 +103,7 @@ available.
* **Atom** - `linter-luacheck`
* **Sublime** - `SublimeLinter-luacheck`
## Checking commits with Travis
## Checking Commits with Travis
If your project is public and is on Github, you can use TravisCI - a free service
to run jobs on commits to check them. This means that every commit you push will

View File

@ -7,34 +7,185 @@ idx: 6.4
## Introduction
Unit tests are an essential tool in proving and resuring yourself that your code
Unit tests are an essential tool in proving and reassuring yourself that your code
is correct. This chapter will show you how to write tests for Minetest mods and
games using busted, and how to structure your code to make this easier - Writing
unit tests for functions where you call Minetest functions is quite difficult,
but luckily [in the previous chapter](mvc.html), we discussed how to make your
code avoid this.
games using busted. Writing unit tests for functions where you call Minetest
functions is quite difficult, but luckily [in the previous chapter](clean_arch.html)
we discussed how to make your code avoid this.
* [Installing Busted](#installing-busted)
* [Windows](#windows)
* [Linux](#linux)
* [Your First Test](#your-first-test)
* [Mocking: Using External Functions](#mocking-using-external-functions)
* [Checking Commits with Travis](#checking-commits-with-travis)
* [Conclusion](#conclusion)
## Installing Busted
### Windows
First you'll need to install LuaRocks.
*Todo. No one cares about windows, right?*
* Windows: Follow the [installation instructions on LuaRock's wiki](https://github.com/luarocks/luarocks/wiki/Installation-instructions-for-Windows).
* Debian/Ubuntu Linux: `sudo apt install luarocks`
### Linux
First you'll need to install LuaRocks:
sudo apt install luarocks
You can then install Busted globally:
Next you should then install Busted globally:
sudo luarocks install busted
Check that it's installed with the following command:
Finally, check that it is installed:
busted --version
## Your First Test
Busted is Lua's leading unit test framework. Busted looks for Lua files with
names ending in `_spec`, and then executes them in a standalone Lua environment.
mymod/
├── init.lua
├── api.lua
└── tests
└── api_spec.lua
### init.lua
{% highlight lua %}
mymod = {}
dofile(minetest.get_modpath("mymod") .. "/api.lua")
{% endhighlight %}
### api.lua
{% highlight lua %}
function mymod.add(x, y)
return x + y
end
{% endhighlight %}
### tests/api_spec.lua
{% highlight lua %}
-- Look for required things in
package.path = "../?.lua;" .. package.path
-- Set mymod global for API to write into
_G.mymod = {} --_
-- Run api.lua file
require("api")
-- Tests
describe("add", function()
it("adds", function()
assert.equals(2, mymod.add(1, 1))
end)
it("supports negatives", function()
assert.equals(0, mymod.add(-1, 1))
assert.equals(-2, mymod.add(-1, -1))
end)
end)
{% endhighlight %}
You can now run the tests by opening a terminal in the mod's directory and
running `busted .`
It's important that the api file doesn't create the table itself, as globals in
Busted work differently. Any variable which would be global in Minetest is instead
a file local in busted. This would have been a better way for Minetest to do things,
but it's too late for that now.
Another thing to note is that any files you're testing should avoid calls to any
functions not inside of it. You tend to only write tests for a single file at once.
## Mocking: Using External Functions
Mocking is the practice of replacing functions that the thing you're testing depends
on. This can have two purposes - firstly, the function may not be available in the
test environment. Secondly, you may want to capture calls to the function and any
passed arguments.
If you follow the advice in the [Clean Architectures](clean_arch.html) chapter,
you'll already have a pretty clean file to test. You will still have to mock
things not in your area however - for example, you'll have to mock the view when
testing the controller/API. If you didn't follow the advice, then things are a
little harder as you may have to mock the Minetest API.
{% highlight lua %}
-- As above, make a table
_G.minetest = {}
-- Define the mock function
local chat_send_all_calls = {}
function minetest.chat_send_all(name, message)
table.insert(chat_send_all_calls, { name = name, message = message })
end
-- Tests
describe("list_areas", function()
it("returns a line for each area", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
assert.equals(2, #chat_send_all_calls)
end)
it("sends to right player", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
for _, call in pairs(chat_send_all_calls) do --_
assert.equals("singleplayer", call.name)
end
end)
-- The above two tests are actually pointless, as this one tests both things
it("returns correct thing", function()
chat_send_all_calls = {} -- reset table
mymod.list_areas_to_chat("singleplayer", "singleplayer")
local expected = {
{ name = "singleplayer", message = "Town Hall (2,43,63)" },
{ name = "singleplayer", message = "Airport (43,45,63)" },
}
assert.same(expected, chat_send_all_calls)
end)
end)
{% endhighlight %}
## Checking Commits with Travis
The Travis script from the [Error Checking](luacheck.html)
chapter can be modified to also run Busted.
{% highlight yml %}
language: generic
sudo: false
addons:
apt:
packages:
- luarocks
before_install:
- luarocks install --local luacheck && luarocks install --local busted
script:
- $HOME/.luarocks/bin/luacheck --no-color .
- $HOME/.luarocks/bin/busted .
notifications:
email: false
{% endhighlight %}
## Conclusion
Unit tests will greatly increase the quality and reliability of your project if used
well, but they require you to structure your code in a different way than usual.
For an example of a mod with lots of unit tests, see
[crafting by rubenwardy](https://github.com/rubenwardy/crafting).