godot-bootstrap
godot-bootstrap copied to clipboard
Parse tests out of scripts
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 usingcall
. - 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).
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).
What about simply using get_method_list
for get the methods, then parse it instead? :smile:
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.
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.
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.
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.