godot-bootstrap icon indicating copy to clipboard operation
godot-bootstrap copied to clipboard

Parse tests out of scripts

Open bitwes opened this issue 8 years ago • 6 comments

I came across your repo when searching for godot typeof examples. I wasn't sure how else to share this, so sorry for using an issue. I've created my own unit testing tool as well. I'm really interested in your approach. I thought I'd share with you how I parse out the tests from the files. Here's the code.

#-------------------------------------------------------------------------------
#Parses out the tests based on the _test_prefix.  Fills the _tests array with
#instances of OneTest.
#-------------------------------------------------------------------------------
func _parse_tests(script):
    var file = File.new()
    var line = ""
    var line_count = 0

    file.open(script, 1)
    while(!file.eof_reached()):
        line_count += 1
        line = file.get_line()
        #Add a test
        if(line.begins_with("func " + _test_prefix)):
            var from = line.find(_test_prefix)
            var len = line.find("(") - from
            var new_test = OneTest.new()
            new_test.name = line.substr(from, len)
            new_test.line_number = line_count
            _tests.append(new_test)

    file.close()

You should be able to adapt this, but here's a few notes

  • The script parameter is the path to the test script (i.e. 'res://unit_tests/test_this_thing.gd')
  • OneTest is a simple struct class to hold info about each test. I keep an array of them (_tests) and then loop through them later calling them using call.
  • test_prefix holds 'test' in it by default. I just used a variable in case someone wanted to use something else.

I've written 46 test scripts with about 1000 tests and this logic has worked just fine. Hope it helps.

If you're interested, my testing tool can be found at https://bitbucket.org/bitwes/gut. I'm working on a 3.0 version now and will be moving it to github when it is done (by the end of the week at the latest).

bitwes avatar Aug 16 '16 03:08 bitwes

Thanks for the suggestion. That's an interesting approach - to actually parse out the script itself. I never like the idea of needing to explicitly call out the list of test functions, so this would be a big help.

The function parsing would need to be a bit more flexible, because for proper grammar handling it would need to be able to deal with spaces correctly (e.g. "func test_a (x)"), but that can easily be dealt with through regular expressions. I don't think that gdscript has any situations where there can be free-form text with "func" at the start of a line, so this would work.

A further simplification would be to have the base test class call "get_script()" in the _init function, and parse the text from the returned string. That way the test class could override this behavior if it wanted to (such as to force tests to run in a specific order, or if the user just wants to be contrary and not use the naming convention).

groboclown avatar Aug 16 '16 06:08 groboclown

What about simply using get_method_list for get the methods, then parse it instead? :smile:

bojidar-bg avatar Aug 16 '16 06:08 bojidar-bg

It's too easy. That's just what they're expecting us to do.

No, reading the get_method_list and calling the methods that start with test_ is the better option.

groboclown avatar Aug 16 '16 14:08 groboclown

Either I didn't know about it or the methods don't come back in the order they are in the file. That's all speculation though, I wrote that's long time ago. I do spit out the line number for the test when a test fails though, which is handy when dealing with a test script with a lot of tests.

bitwes avatar Aug 16 '16 22:08 bitwes

As a historical note, the Godot 1.x code line didn't provide a get_method_list function, so that would explain why we went through these pains to find the list of tests to run. With 2.x, that's now solved.

groboclown avatar Aug 18 '16 13:08 groboclown

I've updated the unit_test component to how support auto-detection of test methods, as well as some other improvements, such as more matchers, a new check method, more flexibility in the error reporting, and better test case skipping.

groboclown avatar Aug 18 '16 21:08 groboclown