CodeaUnit - Unit Test Framework

Hey all,

I am a big fan of Codea and coding in general. I am also a big proponent of unit testing (TDD preferably). Since the app doesn’t have a unit test framework built in, I recently created one specifically for Codea. If you have a desire for proper unit testing in your projects. Checkout CodeaUnit on GitHub.

CodeaUnit is designed as a library that you simply add as a dependency to any of your own projects that you want unit testing abilities in. It adds a ‘CodeaUnit Runner’ button to the parameters view when running your code. The runner finds all functions in the app (all tabs) that start with ‘test’ and runs them for you. All of the features are detailed further on GitHub.

Enjoy, contribute, whatever :slight_smile:

thank you. I really miss some nice way to manage unit tests with Codea. I have tried your code, but there is a problem with my other rules: i try to never create globals, so for instance as in the code below

xfc = {}

local myClass = class()
xfc.myClass = myClass

function myClass.testCodeaUnitFunctionality()
    CodeaUnit.detailed = true

    _:describe("CodeaUnit Test Suite", function()

        _:before(function()
            -- Some setup
        end)

        _:after(function()
            -- Some teardown
        end)

        _:test("Equality test", function()
            _:expect("Foo").is("Foo")
        end)

        _:test("Negation test", function()
            _:expect("Bar").isnt("Foo")
        end)

        _:test("Containment test", function()
            _:expect({"Foo", "Bar", "Baz"}).has("Foo")
        end)

        _:test("Thrown test", function()
            _:expect(function()
                error("Foo error")
            end).throws("Foo error")
        end)

        _:ignore("Ignored test", function()
            _:expect("Foo").is("Foo")
        end)

        _:test("Failing test", function()
            _:expect("Foo").is("Bar")
        end)

    end)
end

with this way, your test wont run. Could you propose something? Since it is also quite important to limit the number of globals…
Thanks.

pardon my ignorance, but what is the purpose of a Unit Test?

‘unit tests’ are small test on small functionnalities of your code. Then, when you change something, if you make small mistakes, they wont be undetected.

@jakesankey: Looks very nice, I’ll try it when next I get back to Codea.

@matkatmusic: unit tests are used to determine whether the code we write is doing what we think. For example, if we have a need to make a moving object face forward, using some little function that we write, we might write a unit test to check whether the function works.

I find that with Codea it often seems easier just to look and see, or to write out some trace info, so I often think unit testing isn’t worth the effort in Codea.

The funny thing is that when I have a better testing tool and practice using it, I find more testing to be useful, and change the balance between when I test and when I do not. So I look forward to trying this one.

I hated unit testing. Too much time was spent on paperwork figuring out what the tests were going to do and writing all the steps to run and what the results were supposed to be. I felt it was a waste of time that could be spent on writing code, that’s why someone else did the unit testing on my code. It was important to do, but I wasn’t going to do all that paperwork.

@Jmv38 - This is a very early version, especially for the runner. I agree with your objection of global functions. Couple things to consider that I was thinking about while writing this…

If you have a class MyClass, instead of putting the test functions inside of MyClass, create a new class/tab MyClassTest which contains the test functions. No, this route doesn’t eliminate the global functions but it does isolate them in the code base. For me, a solid test suite is worth having some globals hanging out there as long as they are not mixed in the ‘production’ code. Basically, better than nothing :wink:

Also, the global ‘function testFoo()’ syntax is simply a requirement for the CodeaUnit runner to find the tests. You certainly don’t have to use the runner. You can do what you did in your example above and simply execute the tests yourself by manually calling testCodeaUnitFunctionality programmatically (or wire up your own parameter.action button that triggers your suite).

The runner is still pretty limited in capability and I hope to make it smarter going forward which hopefully the Codea community can help with. Removing the necessity of having global functions will be a top priority. Perhaps enforcing that they be put into classes with Test in the name, the runner could look for that, create and instance and execute methods with test in their names. I will definitely update you all here whenever I push new versions.

Thanks for the feedback!

@jakesankey thanks for the advice on how to embed tests. I feel quite often the need for guidance by experienced people on best practices, so your arguments and framework suggestion will help me.
Thanks.

@dave1707 - I’ve definitely been there. Focusing on TDD (write the tests before the code) changed everything for me. Codea aside, in large enterprise applications with many devs, a solid test-driven code base with high test coverage gives you so much more confidence in your product. You can stop focusing on defects and maintenance and start focusing on delivery. It gives you the ability to refactor with confidence and push out new features with far less concern of bugs. Just my experience :slight_smile:

In Codea, with small code bases and mostly experimental code, CodeaUnit is more of a luxury for those of us that are used to TDD. TDD is so engrained in me through my work experience, I cringe when I have to write code without it. Nothing like seeing a whole bunch of automated tests run and pass :slight_smile:

btw, your post came right at the same time i was writing unit tests for my buttons library. What a coencidence!

@jakesankey: copied and pasted it in and works as advertised. Notation is a bit weird, but so is RSpec :slight_smile: I’ll give it a go for something real if I ever get back to Codea. Lots of stuff on the plate just now.

@dave1707: I hated old style unit tests as well. I also hated the d*** testers coming in to tell me there was a bug in my code. Had I been more perfect, they might have quit in frustration but I never got there.

TDD style is different. With a nice tool and some practice, I can express my next planned steps and design ideas in a little test, then make it work.

For those interested, check ronjeffries.com and the tdd category.

@RonJeffries - The notation will grow on you I think :slight_smile: It is consistent with the big hitters in the NodeJS (and JS in general) world like Mocha and Jasmine, which I have been using a lot lately so I figured I’d follow in those functional footsteps instead of reinventing the wheel. Something they do differently is they make ‘describe’, ‘expect’, ‘test’ global for shortened syntax whereas I opted for the object instance (like _:expect). I’m not loving typing _: so often but until I figure out a better way to manage multiple suites with global state like those other frameworks, it’ll have to do.

By the way @RonJeffries, to make things awkward, it’s an honor to virtually speak with you. I’m a fan of your work and a bit star struck honestly! :slight_smile: I work in an XP environment and have read many of your’s and your colleagues works. Many of the practices we promote at my company and on my teams are those refined by you and yours!

1 Like

Thanks … I try to be useful. But an honor? I’m just some old guy with a keyboard and lots of miles. :slight_smile:

I’m glad you’re having success with some of the ideas I’ve written about.

@jakesankey: I put an experimental testing framework thing up on github that you might find interesting. It works by having tests be subclasses of a provided class TestCase, which might help with the issue of test methods needing to be global.

Or it might be useless. Let me know …

Thanks @RonJeffries. I can definitely use this concept. This is sort of where my mind was going as I was thinking about the globals. I’ll toy with it when I get some time.

Hm. I needed some testing and linked in CodeaUnit. It fails right off the bat with “attempt to call a table value” and no stack traceback. some incompatibility with modern Codea versions but no idea just what’s up. I’m on a mission so may not shave this yak just now. Advice welcome.

Whoa! When I paste the CodeaUnit code directly into a tab, it works. When I use it as a dependency, it doesn’t work. Has something changed in how dependencies work?

1 Like