Sunday 11 September 2016

Learning Lua - Test Doubles

I was able to spend some time learning Lua this week and made a little progress with my stockfetch project which am using to answer Busted or LuaUnit?

This week I needed to mock some functions to write some tests. Lua, as I had expected, makes it easy to replace functions with test "doubles". I was expecting that Busted would make it easy to "mock" a function. What I found is that Busted definitions of "stub" and "mock" are not the ones that I understand. 

My understanding was based on four types of test "doubles" - fakes, stubs, mocks and spies. Fakes are functions that provide an implementation just for testing that would not be used in production.  Stubs return a known value or perform a known side effect. Mocks are like stubs with the added functionality of being able to query interaction with them. (Such as what arguments they were called with, how often they were called and what they returned.) Spies could be considered as mocks which additionally call the actual function.

From my current understanding, in Busted spies are like the spies that I understand. It seems that Busted stubs appear to be like the mocks with which I am familiar but without the ability to specify a return value (or values). From the docs, Busted mocks are tables whose functions have been wrapped in spies or stubs.

The different terminology isn't a problem but not being able to specify a return value from a test "double" leads to additional work. (It might actually be possible to do so in Busted but I haven't been able to find out how just yet.)

I had expected to "roll my own" test doubles with LuaUnit but having to do part of the job myself with Busted means that there still isn't much to choose between them.

In one test, that I wrote I wanted to check that a function was called five times and have it return 0 each time it was called.

This is how I achieved that using Busted:

        saveProcessTicker = stockfetch.processTicker
    stockfetch.processTicker = function () 
      return 0 
    end 
    spy.on(stockfetch, "processTicker")
    assert.equal(0, stockfetch.run('fixtures/mixedTickers.txt'))
    assert.spy(stockfetch.processTicker).was.called(5)
    stockfetch.processTicker:revert()
    stockfetch.processTicker = saveProcessTicker

This is the LuaUnit equivalent:

    saveProcessTicker = stockfetch.processTicker
  local processTickerCalled = 0
  stockfetch.processTicker = function ()
    processTickerCalled = processTickerCalled + 1 
    return 0 
  end 
  luaunit.assertEquals(stockfetch.run('fixtures/mixedTickers.txt'), 0);
  luaunit.assertEquals(processTickerCalled, 5)
  stockfetch.processTicker = saveProcessTicker

The main difference being needing to "manually" count the number of times that the function was called with LuaUnit.

I will be looking at using test doubles with builtin modules such as IO next.

2 comments:

Michael Blakesley said...

Thanks for this post! I was struggling to understand Busted's stubs & mocks, especially since I didn't see a way to specify return values for a stubbed function. Your example seems like the best way to do it.

Peter W A Wood, Programmer said...

I'm happy the post helped. I'm not sure if the example is the best way but it did work for me.