blog/testing-with-lua.post
2015-01-02 21:04:36 +01:00

121 lines
4 KiB
Text

;;;;;
title: Testing with Lua
tags: projects, lua, testing, ci, avandu-lua
date: 2014-06-30 23:32
format: md
;;;;;
Last time I wrote about my project
[avandu-lua](https://ryuslash.org/blog/?p=51) and I mentioned how I
was having some trouble testing the different types of functions. I've
since found a way to mock the functions in such a way that I can
safely test functions with IO operations without having to actually
perform them. It seems that Lua modules are mutable. Perhaps this
isn't strange given that Lua modules are basically tables, but I
hadn't considered it before. I'm not entirely sure if it is a language
feature or just something that happens to be true right now, so this
method of mine might soon become useless.
# Testing operations
So, to test these functions that would normally have side-effects or
would require a lot of extra work setting up to work correctly, we
basically have to replace the existing functions. Normally in a
running program you really wouldn't want to do this, save for when you
have dynamic scope, which I haven't yet found in Lua.
So I want to test that everything works properly when the `io.access`
function reports it can't access a certain file, I'd change the
function like so:
```
-- You must first require it, so you have the same module.
local posix = require 'posix'
-- ...
posix.access = function ()
return false
end
```
This way I know what the function will do, when it eventually gets
called.
# Travis-CI
After finally getting some tests in my project and making sure that I
have full test coverage of my module, I thought it would be fun to see
if I could automatically test everything with travis-ci. It was a
little challenging because I don't normally run Ubuntu or Debian, so I
don't know what they name their packages, and one of my dependencies
(luasec) had some trouble finding the libssl library.
After a little poking around, a few retries and a false-success, it's
now finally running:
<div class="center">
<a href="https://travis-ci.org/ryuslash/avandu-lua">
<img src="https://travis-ci.org/ryuslash/avandu-lua.svg?branch=master" />
</a>
</div>
My `.travis.yml` is pretty simple:
```
language: erlang
env:
- LUA="lua"
branches:
except:
- gh-pages
install:
- sudo apt-get update
- sudo apt-get install luarocks libssl1.0.0
- sudo luarocks install busted
- sudo luarocks install luasocket
- sudo luarocks install luasec OPENSSL_LIBDIR=/usr/lib/x86_64-linux-gnu
- sudo luarocks install luajson
- sudo luarocks install luaposix
script: "busted -m 'lua/?.lua' -o TAP"
# ...
```
I'm using the `erlang` environment, because there isn't a Lua one
(yet). I've written my library for lua, not luajit, so busted needs to
know which to run, it always runs luajit first it seems. I don't need
the tests to be run again when the `gh-pages` branch is updated, since
that has nothing to do with the code itself, I would actually like to
have tests run on all other branches.
Then we get to the dependencies. Nothing major except for the luasec
dependency. I'm not entirely sure how long that `OPENSSL_LIBDIR` will
remain where it is now, but it works for now. I didn't discover the
location myself, I found it on
[someone else's](https://github.com/ignacio/redis-luanode/blob/a50a7e5a9d0bd0c61b6ce7e445b278f2f184c792/.travis.yml#L41)
`.travis.yml` as a comment.
Lastly we have the script. Since the tests live in `/spec` and the
code lives in `/lua` I run the tests from the project root and include
the `lua` directory in the module path. I use TAP output because with
the default output failures also return `0`, when a failure occurs
with the TAP output, a non-0 exit status is returned and travis knows
they didn't pass. That is why build 6 passed even though there was
still a failed test.
The rest is notification settings which isn't interesting enough to
duplicate here.
# Still to do
Now I should start expanding it a little. Well, actually I *still*
need to add the proper license information.
<!-- Local Variables: -->
<!-- mode: markdown -->
<!-- End: -->