Writing unit tests within love code

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
soulmata
Prole
Posts: 31
Joined: Sat Jan 26, 2013 8:14 am
Contact:

Writing unit tests within love code

Post by soulmata »

Hello,

I have some questions regarding best practices or at least "acceptable" practices for writing unit tests for LUA code written specifically for love. I'll preface this by saying I'm totally a goal-oriented person, so my primary interests are in producing code that does what I intend it to do. I'm generally not interested in writing elegant or clever code, merely functional. Nevertheless, good testing coverage is very useful to me as it helps me prove my code is, indeed, functional. OK. That said.

The question. Is the method of mock/testing below suitable for love, and if not, any suggestions?

My method.

1) All functions I write will return some return value, even if I don't actually need it in the game
2) As I am not responsible for love.* functions, I do not test them or attempt to test them
3) All functions I write are written in such a fashion to test their individual components

How I do it:
I have a "tests.lua" module which includes all modules for my game, as well as LuaUnit. tests.lua is only used through lua, the love engine has no knowledge of it. It resembles this:

Code: Select all

-- tests.lua
love = {}
require('main')           -- main
require('logging')        -- our own logging
require('persistence')    -- module to serialize data structures and write them to disk
require('modules/luaunit/luaunit') -- testing module
... et cetera.
Now, many of my modules will access global variables. I know this isn't super ideal. But, for even those that don't, some still will try to use functions provided by love. Since these functions aren't part of my scope, and likely won't even function, I mock any love functions while testing. i.e.:

Code: Select all

-- tests.lua

-- Mocked love functions - is there a better way to do this?
love = {
  graphics = {
    newImage = function() return end,
    newFont  = function() return end,
  },
  mouse = {
    setVisible = function() return end,
  }
}
Then I just write tests as normal, like:

Code: Select all

-- tests.lua

load_mock_data()
-- Test Logging module
Test_f_colony_logging_tests = {}
  function Test_f_colony_logging_tests:testGoodData()
    test_message = 'test message'
    test_level   = 'warn'
    rv, err = f_colony_log(test_message, test_level)
    assertEquals ( type(rv), 'number')
    assertEquals ( rv, 0 )
    assertEquals ( type(err), 'nil')
  end
LuaUnit:run()
So far, I've found I can write unit tests for virtually any function write, and nearly every component of it. I'm careful to make sure to validate my inputs, die on data I can't handle, et cetera. The only "messy" part about it, I think, is that I have to mock the love functions to mocked responses. I see that as OK because I don't maintain / don't care about testing the love functions, I only care about how my own code interacts with them - so if a love function should return an image, I mock it in my test suite to return test image data.

It does mean there are some cases I can't test - like if I tell love to load a font file, and the font file doesn't exist, I'm not able to test that. That's not ideal, and I haven't thought of a good way around it yet, but I'm open to suggestions. One way I am considering is a set of functional tests I can trigger in-game, so I have full access to the love suite. It also means I'd have to execute both unit tests then run functional tests in-game(I can certainly automate that, of course). I suppose if love can take command-line arguments and my game can access them, I could even execute the tests with the game running - but then that means no headless testing.
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
User avatar
markgo
Party member
Posts: 190
Joined: Sat Jan 05, 2013 12:21 am
Location: USA

Re: Writing unit tests within love code

Post by markgo »

You may be interested in this how this man does it: https://bitbucket.org/blprice61/dark-st ... ve-ike/src

Hope it gives you some ideas. Good luck.
User avatar
soulmata
Prole
Posts: 31
Joined: Sat Jan 26, 2013 8:14 am
Contact:

Re: Writing unit tests within love code

Post by soulmata »

It looks like he took the same approach I did, and mocks all of the needed love functions. At least I know I'm on the right track.

Does anyone else here have experiencing writing unit tests for their love code?
Endless Dark: An existential horror game written in LOVE in which you are tasked with keeping a sleeper colony ship intact.
User avatar
ejmr
Party member
Posts: 302
Joined: Fri Jun 01, 2012 7:45 am
Location: South Carolina, U.S.A.
Contact:

Re: Writing unit tests within love code

Post by ejmr »

Recently I have been using Busted for unit testing. Here is project where I use it, a component that is part of the game I am working on. So far I’ve been happy with the combination of Busted and LÖVE. It provides ways to create stubs for LÖVE functions but I have not thoroughly explored how well that works in practice, and I suspect that may be the make-or-break aspect of using Busted together with LÖVE. I have heard good things about Telescope but personally I’ve not used it for anything LÖVE-related.
ejmr :: Programming and Game-Dev Blog, GitHub
南無妙法蓮華經
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Writing unit tests within love code

Post by kikito »

Similar approach from me on the anim8 tests: love mocks and example of use.

I think that tests are great for libraries. Writing tests for a whole game will be very challenging, unless you manage to split your code very carefully, so that in fact your game becomes a "bunch of libraries acting together". Good luck!
When I write def I mean function.
mccarthy
Prole
Posts: 3
Joined: Mon Dec 18, 2017 11:35 am

Re: Writing unit tests within love code

Post by mccarthy »

Highjacking this thread as it seems most relevant to my question.

I'm currently attempting to write some tests for some procedurally generated terrain in a game I'm working on. I make use of the love.math.noise(x, y) function in the terrain generation. Naturally, when I create a new terrain object in the setup for my tests, busted has no idea about the love.math table.

Is there a way to expose the various love functions? I know in this specific instance I could get around it by writing my own simplex noise lib and using that, but I figured this must be a problem people have come across before and hopefully there is a solution already out there.

Thanks in advance for any help and advice!
User avatar
pgimeno
Party member
Posts: 3673
Joined: Sun Oct 18, 2015 2:58 pm

Re: Writing unit tests within love code

Post by pgimeno »

mccarthy wrote: Sat Sep 14, 2019 4:50 pm Is there a way to expose the various love functions? I know in this specific instance I could get around it by writing my own simplex noise lib and using that, but I figured this must be a problem people have come across before and hopefully there is a solution already out there.
You can require love:

Code: Select all

package.preload.love = package.loadlib('/path/to/liblove-11.2.so', 'luaopen_love')
require 'love'
require 'love.math'
Or you can ditch busted and roll your own unit testing.
mccarthy
Prole
Posts: 3
Joined: Mon Dec 18, 2017 11:35 am

Re: Writing unit tests within love code

Post by mccarthy »

Thanks for the response!

I spotted your reply here after posting, but still having some issues. I've renamed liblove.so to love.so, and put it in the root directory of my LÖVE project (just for convenience at this point), but still seeing the following error:

Code: Select all

spec/map/terrain_spec.lua:2: error loading module 'love' from file './love.so':
dlopen(./love.so, 6): no suitable image found.  Did find:
./love.so: unknown file type, first eight bytes: 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00
I should mention I'm using OSX and not a Linux distro, which may be an issue here. At this point I may well just roll my own unit testing framework, though Busted looks pretty useful so it'd be nice to get that up and running.

Again, your help is very much appreciated!
User avatar
pgimeno
Party member
Posts: 3673
Joined: Sun Oct 18, 2015 2:58 pm

Re: Writing unit tests within love code

Post by pgimeno »

I wonder if you're using the right file and the right architecture. Wasn't it .dylib for Mac? Not sure about that, I may be outdated. 0x7F 0x45 0x4C 0x46 0x01 0x01 0x01 0x00 means ELF 32-bit little-endian; there doesn't seem to be anything wrong there if Mac can load 32-bit ELF shared libraries.

EDIT: After unzipping the MacOS distribution, it appears to me that the file you want is love.app/Contents/Frameworks/love.framework/Versions/A/love - I'm not sure, but the 'file' Linux utility identifies it as: "Mach-O 64-bit x86_64 dynamically linked shared library, flags:<NOUNDEFS|DYLDLINK|TWOLEVEL|WEAK_DEFINES|BINDS_TO_WEAK|NO_REEXPORTED_DYLIBS>"
TheHUG
Citizen
Posts: 62
Joined: Sun Apr 01, 2018 4:21 pm

Re: Writing unit tests within love code

Post by TheHUG »

for tests where I need access to love functions I use: https://love2d.org/forums/viewtopic.php?t=75192

Another option would be to mock the functions you need
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 2 guests