diff --git a/.gutconfig.json b/.gutconfig.json index f35f1f33..8cb7e852 100644 --- a/.gutconfig.json +++ b/.gutconfig.json @@ -7,6 +7,7 @@ "res://test/integration/" ], "should_maximize": false, + "hide_orphans": true, "should_exit": true, "ignore_pause": true, "log_level": 3, diff --git a/CHANGES.md b/CHANGES.md index 657c2c59..1d49e08b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). * __Issue 485__ GUT prints a warning and ignores scripts that do not extend `GutTest`. * A lot of internal reworkings to simplify logging and info about test statuses. The summary changed and the final line printed by GUT is now the highest severity status of the run (i.e. failed > pending/risky > passed). * __Issue 503__ Fixed issue where GUT would not find script object when doubling PackedScenes. +* __Port PR 409__ GUT's simulate function can now check `is_processing` and `is_physics_processing` when running thier respective methods. # 9.0.1 diff --git a/README.md b/README.md index ac20177c..7c70625c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +![gut logo](images/gut_logo_256x256.png) # Gut 9.1.0 (Godot 4.1) GUT (Godot Unit Test) is a unit testing framework for the [Godot Engine](https://godotengine.org/). It allows you to write tests for your gdscript in gdscript. @@ -15,14 +16,13 @@ If you would like to help support GUT check out my game [Country or State](https # Features * Godot 4.0 -* [Simple install](https://github.com/bitwes/Gut/wiki/Install) via the Asset Library. -* A plethora of [asserts and utility methods](https://github.com/bitwes/Gut/wiki/Asserts-and-Methods) to help make your tests simple and concise. -* Support for [Inner Test Classes](https://github.com/bitwes/Gut/wiki/Inner-Test-Classes) to give your tests some extra context and maintainability. -* Doubling: [Full](https://github.com/bitwes/Gut/wiki/Doubles) and [Partial](https://github.com/bitwes/Gut/wiki/Partial-Doubles), [Stubbing](https://github.com/bitwes/Gut/wiki/Stubbing), [Spies](https://github.com/bitwes/Gut/wiki/Spies) -* Command Line Interface [(CLI)](https://github.com/bitwes/Gut/wiki/Command-Line) -* [Parameterized Tests](https://github.com/bitwes/Gut/wiki/ParameterizedTests) -* [Export results](https://github.com/bitwes/Gut/wiki/Export-Test-Results) in standard JUnit XML format. -* [Distribute your tests](https://github.com/bitwes/Gut/wiki/Running-On-Devices) with your project and run them on any platform Godot supports. +* [Simple install](https://bitwes.github.io/GutWiki/Godot4/Install) via the Asset Library. +* A plethora of [asserts and utility methods](https://bitwes.github.io/GutWiki/Godot4/Asserts-and-Methods) to help make your tests simple and concise. +* Support for [Inner Test Classes](https://bitwes.github.io/GutWiki/Godot4/Inner-Test-Classes) to give your tests some extra context and maintainability. +* Doubling: [Full](https://bitwes.github.io/GutWiki/Godot4/Doubles) and [Partial](https://bitwes.github.io/GutWiki/Godot4/Partial-Doubles), [Stubbing](https://bitwes.github.io/GutWiki/Godot4/Stubbing), [Spies](https://bitwes.github.io/GutWiki/Godot4/Spies) +* Command Line Interface [(CLI)](https://bitwes.github.io/GutWiki/Godot4/Command-Line) +* [Parameterized Tests](https://bitwes.github.io/GutWiki/Godot4/ParameterizedTests) +* [Export results](https://bitwes.github.io/GutWiki/Godot4/Export-Test-Results) in standard JUnit XML format. More info can be found in the [wiki](https://github.com/bitwes/Gut/wiki). @@ -30,10 +30,10 @@ More info can be found in the [wiki](https://github.com/bitwes/Gut/wiki). # Getting Started -* [Install](https://github.com/bitwes/Gut/wiki/Install) -* [Quick Start](https://github.com/bitwes/Gut/wiki/Quick-Start) -* [Creating Tests](https://github.com/bitwes/Gut/wiki/Creating-Tests) -* [Asserts and Methods](https://github.com/bitwes/Gut/wiki/Asserts-and-Methods) +* [Install](https://bitwes.github.io/GutWiki/Godot4/Install) +* [Quick Start](https://bitwes.github.io/GutWiki/Godot4/Quick-Start) +* [Creating Tests](https://bitwes.github.io/GutWiki/Godot4/Creating-Tests) +* [Asserts and Methods](https://bitwes.github.io/GutWiki/Godot4/Asserts-and-Methods) # VSCode Extension diff --git a/addons/gut/plugin.cfg b/addons/gut/plugin.cfg index ddf49e72..40e8b8f9 100644 --- a/addons/gut/plugin.cfg +++ b/addons/gut/plugin.cfg @@ -3,5 +3,5 @@ name="Gut" description="Unit Testing tool for Godot." author="Butch Wesley" -version="9.0.1" +version="9.1.0" script="gut_plugin.gd" diff --git a/addons/gut/stub_params.gd b/addons/gut/stub_params.gd index 1f4450d3..3d1dd75e 100644 --- a/addons/gut/stub_params.gd +++ b/addons/gut/stub_params.gd @@ -40,7 +40,7 @@ func _init(target=null,method=null,subpath=null): _lgr.warn(str(target, ' is not a valid path')) if(stub_target is PackedScene): - stub_target = _utils.get_scene_script_object(stub_target) + stub_target = GutUtils.get_scene_script_object(stub_target) # this is used internally to stub default parameters for everything that is # doubled...or something. Look for stub_defaults_from_meta for usage. This diff --git a/addons/gut/utils.gd b/addons/gut/utils.gd index f8fd749c..d4369e60 100644 --- a/addons/gut/utils.gd +++ b/addons/gut/utils.gd @@ -217,7 +217,7 @@ var CollectedScript = load('res://addons/gut/collected_test.gd') var GutScene = load('res://addons/gut/GutScene.tscn') # Source of truth for the GUT version -var version = '9.0.1' +var version = '9.1.0' # The required Godot version as an array. var req_godot = [4, 1, 0] diff --git a/asset_lib_icon.png b/asset_lib_icon.png deleted file mode 100644 index 305aebfd..00000000 Binary files a/asset_lib_icon.png and /dev/null differ diff --git a/images/asset_lib_icon.png b/images/asset_lib_icon.png new file mode 100644 index 00000000..53b2f20c Binary files /dev/null and b/images/asset_lib_icon.png differ diff --git a/images/asset_lib_icon.png.import b/images/asset_lib_icon.png.import new file mode 100644 index 00000000..ae10e603 --- /dev/null +++ b/images/asset_lib_icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bui86s2l35d8k" +path="res://.godot/imported/asset_lib_icon.png-cefa1bdba335eb5ed005a2e1bf540000.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/asset_lib_icon.png" +dest_files=["res://.godot/imported/asset_lib_icon.png-cefa1bdba335eb5ed005a2e1bf540000.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/images/gut_icon_128x128.png b/images/gut_icon_128x128.png new file mode 100644 index 00000000..27178277 Binary files /dev/null and b/images/gut_icon_128x128.png differ diff --git a/images/gut_icon_128x128.png.import b/images/gut_icon_128x128.png.import new file mode 100644 index 00000000..80f1d70f --- /dev/null +++ b/images/gut_icon_128x128.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://coy05lhxtq12r" +path="res://.godot/imported/gut_icon_128x128.png-1c1038b9b42c7fa58521b4fa62ec0f6c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/gut_icon_128x128.png" +dest_files=["res://.godot/imported/gut_icon_128x128.png-1c1038b9b42c7fa58521b4fa62ec0f6c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/images/gut_logo.png b/images/gut_logo.png new file mode 100644 index 00000000..44e53879 Binary files /dev/null and b/images/gut_logo.png differ diff --git a/asset_lib_icon.png.import b/images/gut_logo.png.import similarity index 68% rename from asset_lib_icon.png.import rename to images/gut_logo.png.import index 0f87694a..352acff0 100644 --- a/asset_lib_icon.png.import +++ b/images/gut_logo.png.import @@ -2,16 +2,16 @@ importer="texture" type="CompressedTexture2D" -uid="uid://toirmiqhlcnb" -path="res://.godot/imported/asset_lib_icon.png-195a8230d8f4e21994f87ec4f754d7d9.ctex" +uid="uid://dr6c18jg6w3pv" +path="res://.godot/imported/gut_logo.png-647a0efbdd5e0d8d00cef1c7cc7aff8d.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://asset_lib_icon.png" -dest_files=["res://.godot/imported/asset_lib_icon.png-195a8230d8f4e21994f87ec4f754d7d9.ctex"] +source_file="res://images/gut_logo.png" +dest_files=["res://.godot/imported/gut_logo.png-647a0efbdd5e0d8d00cef1c7cc7aff8d.ctex"] [params] diff --git a/images/gut_logo_256x256.png b/images/gut_logo_256x256.png new file mode 100644 index 00000000..c0c4b790 Binary files /dev/null and b/images/gut_logo_256x256.png differ diff --git a/images/gut_logo_256x256.png.import b/images/gut_logo_256x256.png.import new file mode 100644 index 00000000..bd0daf94 --- /dev/null +++ b/images/gut_logo_256x256.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://biw60gwe1vv6w" +path="res://.godot/imported/gut_logo_256x256.png-93763dc74b2a88d4193b01553f406371.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/gut_logo_256x256.png" +dest_files=["res://.godot/imported/gut_logo_256x256.png-93763dc74b2a88d4193b01553f406371.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/images/gut_logo_512x512.png b/images/gut_logo_512x512.png new file mode 100644 index 00000000..d0ddeaca Binary files /dev/null and b/images/gut_logo_512x512.png differ diff --git a/images/gut_logo_512x512.png.import b/images/gut_logo_512x512.png.import new file mode 100644 index 00000000..6e8e2c63 --- /dev/null +++ b/images/gut_logo_512x512.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://m2jo06pvafvb" +path="res://.godot/imported/gut_logo_512x512.png-2b82441fe9284f26dd938b8f90833778.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/gut_logo_512x512.png" +dest_files=["res://.godot/imported/gut_logo_512x512.png-2b82441fe9284f26dd938b8f90833778.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/gut_panel.png b/images/gut_panel.png similarity index 100% rename from gut_panel.png rename to images/gut_panel.png diff --git a/gut_panel.png.import b/images/gut_panel.png.import similarity index 65% rename from gut_panel.png.import rename to images/gut_panel.png.import index 4577287f..001a032a 100644 --- a/gut_panel.png.import +++ b/images/gut_panel.png.import @@ -2,23 +2,23 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cjrdostd274gh" -path="res://.godot/imported/gut_panel.png-51315c4dbef24e14bb14c0ee0272b7be.ctex" +uid="uid://cmsh3ev2pqahl" +path="res://.godot/imported/gut_panel.png-587ffcd50edbcc5c28984221e6ef72b7.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://gut_panel.png" -dest_files=["res://.godot/imported/gut_panel.png-51315c4dbef24e14bb14c0ee0272b7be.ctex"] +source_file="res://images/gut_panel.png" +dest_files=["res://.godot/imported/gut_panel.png-587ffcd50edbcc5c28984221e6ef72b7.ctex"] [params] compress/mode=0 +compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 -compress/bptc_ldr=0 compress/normal_map=0 compress/channel_pack=0 mipmaps/generate=false diff --git a/icon.png b/images/icon.png similarity index 100% rename from icon.png rename to images/icon.png diff --git a/icon.png.import b/images/icon.png.import similarity index 66% rename from icon.png.import rename to images/icon.png.import index a29ee2dc..5cac1746 100644 --- a/icon.png.import +++ b/images/icon.png.import @@ -2,23 +2,23 @@ importer="texture" type="CompressedTexture2D" -uid="uid://cipm0t44xmsyq" -path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" +uid="uid://c5rimjmvly06y" +path="res://.godot/imported/icon.png-b9450fb2459f5b277908511db3d050dd.ctex" metadata={ "vram_texture": false } [deps] -source_file="res://icon.png" -dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] +source_file="res://images/icon.png" +dest_files=["res://.godot/imported/icon.png-b9450fb2459f5b277908511db3d050dd.ctex"] [params] compress/mode=0 +compress/high_quality=false compress/lossy_quality=0.7 compress/hdr_compression=1 -compress/bptc_ldr=0 compress/normal_map=0 compress/channel_pack=0 mipmaps/generate=false diff --git a/BigFont.tres b/test/resources/BigFont.tres similarity index 100% rename from BigFont.tres rename to test/resources/BigFont.tres diff --git a/BigFontTheme.tres b/test/resources/BigFontTheme.tres similarity index 100% rename from BigFontTheme.tres rename to test/resources/BigFontTheme.tres diff --git a/wiki/Asserts-and-Methods.md b/wiki/Asserts-and-Methods.md index 7e5ee877..f5c26721 100644 --- a/wiki/Asserts-and-Methods.md +++ b/wiki/Asserts-and-Methods.md @@ -1,4 +1,4 @@ -
This page has not been updated for GUT 9.0.0 or Godot 4. There could be incorrect information here.
+
This page has not been completely updated for GUT 9.0.0 or Godot 4. There could be incorrect information here.
These are all the methods, bells, whistles and blinky lights you get when you extend the Gut Test Class (`extends GutTest`). All sample code listed for the methods can be found here in [test_readme_examples.gd](https://github.com/bitwes/Gut/blob/master/test/samples/test_readme_examples.gd) @@ -25,10 +25,10 @@ All sample code listed for the methods can be found here in [test_readme_example [replace_node](#replace_node) | [simulate](#simulate) | [stub](#stub) | +[wait_for_signal](#wait_for_signal) | +[wait_frames](#wait_frames) | +[wait_seconds](#wait_seconds) | [watch_signals](#watch_signals) | -[yield_for](#yield_for) | -[yield_frames](#yield_frames) | -[yield_to](#yield_to) | # Gut Utilities @@ -87,6 +87,7 @@ These methods exist on the GUT instance, and not in `test.gd`. They must all be + #### pass_test(text) Useful when you don't have anything meaningful to assert. Any failing asserts within the test will override this. ```gdscript @@ -998,76 +999,17 @@ Print info to the GUI and console (if enabled). You can see examples if this in #### pause_before_teardown() This method will cause Gut to pause before it moves on to the next test. This is useful for debugging, for instance if you want to investigate the screen or anything else after a test has finished executing. See also `set_ignore_pause_before_teardown` -#### yield_for(time_in_seconds) -This simplifies the code needed to pause the test execution for a number of seconds so the thing that you are testing can run its course in real time. There are more details in the Yielding section. It is designed to be used with the `yield` built in. The following example will pause your test execution (and only the test execution) for 2 seconds before continuing. -``` gdscript -class MovingNode: - extends Node2D - var _speed = 2 - - func _ready(): - set_process(true) - - func _process(delta): - set_pos(get_pos() + Vector2(_speed * delta, 0)) - -func test_illustrate_yield(): - var moving_node = MovingNode.new() - add_child_autofree(moving_node) - moving_node.set_pos(Vector2(0, 0)) +#### wait_seconds(time, msg='') +See [Awaiting](Awaiting) - # While the yield happens, the node should move - yield(yield_for(2), YIELD) - assert_gt(moving_node.get_pos().x, 0) - assert_between(moving_node.get_pos().x, 3.9, 4, 'it should move almost 4 whatevers at speed 2') -``` - -#### yield_for(num_frames) -This works similar to `yield_for` except that it will wait for a number of frames to elapse instead of a set amount of time. The frames are counted down by Gut's `_process` method. When the count reaches 0 the `YIELD` signal is emitted. +#### wait_frames(frames, msg='') +See [Awaiting](Awaiting) -#### yield_to(object, signal_name, max_time) -`yield_to` allows you to yield to a signal just like `yield` but for a maximum amount of time. This keeps tests moving along when signals are not emitted. -As a bonus, `yield_to` does an implicit call to `watch_signals` so you can easily make signal based assertions afterwards. -``` gdscript -class TimedSignaler: - extends Node2D - var _time = 0 +#### wait_for_signal(sig, max_wait, msg='') +See [Awaiting](Awaiting) - signal the_signal - func _init(time): - _time = time - - func start(): - var t = Timer.new() - add_child(t) - t.set_wait_time(_time) - t.connect('timeout', self, '_on_timer_timeout') - t.set_one_shot(true) - t.start() - - func _on_timer_timeout(): - emit_signal('the_signal') - -func test_illustrate_yield_to_with_less_time(): - var t = TimedSignaler.new(5) - add_child_autofree(t) - t.start() - yield(yield_to(t, 'the_signal', 1), YIELD) - # since we setup t to emit after 5 seconds, this will fail because we - # only yielded for 1 second via yield_to - assert_signal_emitted(t, 'the_signal', 'This will fail') - -func test_illustrate_yield_to_with_more_time(): - var t = TimedSignaler.new(1) - add_child_autofree(t) - t.start() - yield(yield_to(t, 'the_signal', 5), YIELD) - # since we wait longer than it will take to emit the signal, this assert - # will pass - assert_signal_emitted(t, 'the_signal', 'This will pass') -``` #### double(path_or_class, inner_class_path=null) This will return a double of a class. See [Doubles](Doubles) for more information. diff --git a/wiki/Awaiting.md b/wiki/Awaiting.md new file mode 100644 index 00000000..7fc0b567 --- /dev/null +++ b/wiki/Awaiting.md @@ -0,0 +1,63 @@ +If you aren't sure about coroutines and using `await`, [Godot explains it pretty well](https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#awaiting-for-signals-or-coroutines). GUT supports coroutines, so you can `await` at anytime in your tests. GUT also provides some handy methods to make awaiting easier. + +If you want to pause test execution for some amount of time/frames or until a signal is emitted use `await` and one of GUT's "wait" methods: +* `wait_for_signal` +* `wait_seconds` +* `wait_frames`. + +Calling `await` without using one of GUT's "wait" methods is discouraged. When you use these methods, GUT provides output to indicate that execution is paused. If you don't use them it can look like your tests have hung up. + +# wait_for_signal +``` +wait_for_signal(sig, max_wait, msg=''): +``` +This method will pause execution until a signal is emitted or until `max_wait` seconds have passed, whichever comes first. Using `wait_for_signal` is better than just using `await my_obj.my_signal` since tests will continue to run if the signal is never emitted. + +`wait_for_signal` internally calls `watch_signals` for the object, so you can skip that step when asserting signals have been emitted. + +The optional `msg` parameter is logged so you know why test execution is paused. +``` gdscript +my_object.do_something() +# wait for my_object to emit the signal 'my_signal' +# or 5 seconds, whichever comes first. +await wait_for_signal(my_object.my_signal, 5) +assert_signal_emitted(my_object, 'my_signal', \ + 'Maybe it did, maybe it didnt, but we still got here.') +``` + +# wait_seconds +``` +wait_seconds(time, msg=''): +``` +Sometimes you just want to pause for some amount of time. Use `wait_seconds` instead of making timers. + +The optional `msg` parameter is logged so you know why test execution is paused. +``` gdscript +func test_wait_for_a_bit(): + my_object = ObjectToTest.new() + my_object.do_something() + # wait 2.8 seconds then continue running the test + await wait_seconds(2.8) + gut.assert_eq(my_object.some_property, 'some value') +``` + +# wait_frames +``` +wait_frames(frames, msg=''): +``` + +This is just like `wait_seconds` but instead of counting seconds it counts frames. Due to order of operations, this may wait +/- 1 frames, but sholdn't ever be 0. This can be very useful if you use `call_deferred` in any of the objects under test, or need to wait a frame or two for `_process` to run. + +The optional `msg` parameter is logged so you know why test execution is paused. +``` gdscript +func test_wait_for_some_frames(): + my_object = ObjectToTest.new() + my_object.do_something() + # wait 2 frames before continue test execution + await wait_frames(2) + gut.assert_eq(my_object.some_property, 'some value') +``` + + +# pause_before_teardown +Sometimes, as you are developing your tests you may want to verify something before the any of the teardown methods are called or just look at things a bit. If you call `pause_before_teardown()` anywhere in your test then GUT will pause execution until you press the "Continue" button in the GUT GUI. You can also specify an option to ignore all calls to `pause_before_teardown` through the GUT Panel, command line, or `.gutconfig` in case you get lazy and don't want to remove them. You should always remove them, but I know you won't because I didn't so I made that an option. \ No newline at end of file diff --git a/wiki/Home.md b/wiki/Home.md index 3b597a91..b798fabc 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -2,7 +2,7 @@ This wiki is being updated for the changes made for Godot 4. Any pages with a warning at the top have not been updated yet. For information about the changes in GUT 9 view New-ForGodot-4. -# Gut 9.0.1 +# Gut 9.1.0 (Godot 4.1) GUT (Godot Unit Test) is a utility for writing tests for your Godot Engine game. It allows you to write tests for your gdscripts in gdscript. ### Godot 3.x/4.x @@ -24,7 +24,7 @@ GUT 9 requires Godot 4. GUT 7 requires Godot 3.4. * [Stubbing](Stubbing) * [Parameterized Tests](Parameterized-Tests) * [Simulate](Simulate) -* ~~[Yielding during tests](Yielding)~~ +* [Coroutines and `await` in tests](Awaiting) * [Pre/Post Run Hooks](Hooks) * [Exporting Results](Export-Test-Results) diff --git a/wiki/Simulate.md b/wiki/Simulate.md index 3f430776..d93daff8 100644 --- a/wiki/Simulate.md +++ b/wiki/Simulate.md @@ -1,9 +1,12 @@ -#
This page has not been updated for GUT 9.0.0 or Godot 4. There could be incorrect information here.
-## Simulate +``` +gut.simulate(obj, times, delta, check_is_processing: bool = false): +``` The simulate method will call the `_process` and `_physics_process` on a tree of objects. It will check each object to see if they have either method and run it if it exists. In cases where the object has both it will call `_process` and then `_physics_process` and then move on to the next node in the tree. `simulate` takes in the base object, the number of times to call the methods and the delta value to be passed to `_process` or `_physics_process` (if the object has one). It starts calling it on the passed in object and then moves through the tree recursively calling `_process` and `_physics_process`. The order that the children are processed is determined by the order that `get_children` returns +By default `simulate` will ignore if the object is "processing" or not. When the optional `check_is_processing` is `true`, GUT will check `is_processing` and `is_physics_processing` on each object and will not call their respective methods if the object is not "processing". Remeber, that nodes not in the tree will not be "processing" by default, so you have to add them (use `add_child_autofree` or `add_child_autoqfree`) or call `set_process` or `set_physics_process` before calling `simulate`. + `simulate` will only cause code directly related to the `_process` and `_physics_process` methods to run. Signals will be sent, methods will be called but timers, for example, will not fire since the main loop of the game is not actually running. Creating a test that `yield`s is a better solution for testing such things. Example @@ -69,4 +72,4 @@ func test_does_something_each_loop(): ``` # Where to next? -* [Yielding](Yielding)
+* [Awaiting](Awaiting)
diff --git a/wiki/Yielding.md b/wiki/Yielding.md index 88027f46..7aaa0668 100644 --- a/wiki/Yielding.md +++ b/wiki/Yielding.md @@ -1,48 +1,3 @@ -#
This page has not been updated for GUT 9.0.0 or Godot 4. There could be incorrect information here.
-##
Yielding during a test +Yielding as moved to [Awaiting](Awaiting) -I'm not going to try and explain yielding here. It can be a bit confusing and [Godot does a pretty good job of it already](https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_basics.html#coroutines-with-yield). Gut has support for yielding though, so you can yield at anytime in your test. - -When might you want to yield? Yielding is very handy when you want to wait for a signal to occur instead of running for a finite amount of time. For example, you could have your test yield until your character gets hit by something (`yield(my_char, 'hit')`). An added bonus of this approach is that you can watch everything happen. In your test you create your character, the object to hit it, and then watch the interaction play out. - -Here's an example of yielding to a custom signal. -``` gdscript -func test_yield_to_custom_signal(): - my_object = ObjectToTest.new() - add_child_autofree(my_object) - yield(my_object, 'custom_signal') - assert_true(some_condition, 'After signal fired, this should be true') -``` -### yield_to -Sometimes you need to wait for a signal to be emitted, but you can never really be sure it will, we are making tests after all. You could `yield` to that signal in your test and hope it gets emitted. If it doesn't though, your test will just hang forever. The `yield_to` method addresses this by allowing you to `yield` to a signal or a maximum amount of time, whichever occurs first. You must make sure the 2nd parameter to `yield` is the `YIELD` constant. This constant is available to all test scripts. As an extra bonus, Gut will watch the signals on the object you passed in, so you can save yourself a call to `watch_signals` if you want, but you don't have to. How all this magic works is covered a couple of sections down. - -``` gdscript -# wait for my_object to emit the signal 'my_signal' -# or 5 seconds, whichever comes first. -yield(yield_to(my_object, 'my_signal', 5), YIELD) -assert_signal_emitted(my_object, 'my_signal', \ - 'Maybe it did, maybe it didnt, but we still got here.') -``` - -### yield_for -Another use case I have come across is when creating integration tests and you want to verify that a complex interaction ends with an expected result. In this case you might have an idea of how long the interaction will take to play out but you don't have a signal that you can attach to. Instead you want to pause your test execution until that time has elapsed. For this, Gut has the `yield_for` method. For example `yield(yield_for(5), YIELD)` will pause your test execution for 5 seconds while the rest of your code executes as expected. You must make sure the 2nd parameter to `yield` is the `YIELD` constant. This constant is available to all test scripts. How all this magic works is covered a couple of sections down. - -Here's an example of yielding for 5 seconds. -``` gdscript -func test_wait_for_a_bit(): - my_object = ObjectToTest.new() - my_object.do_something() - #wait 5 seconds - yield(yield_for(5), YIELD) - gut.assert_eq(my_object.some_property, 'some value', 'After waiting 5 seconds, this property should be set') -``` - -### pause_before_teardown -Sometimes it's also helpful to just watch things play out. Yield is great for that, you just create a couple objects, set them to interact and then yield. You can leave the yields in or take them out if your test passes without them. You can also use the `pause_before_teardown` method that will pause test execution before it runs `teardown` and moves onto the next test. This keeps the game loop running after the test has finished and you can see what everything looks like. - -### How Yielding and Gut Works -For those that are interested, Gut is able to detect when a test has called yield because the method returns a special class back (`GDScriptFunctionState`). Gut itself will then `yield` to the `completed` signal provided by the `GDScriptFunctionState` that is returned when your test yielded. It also kicks off a timer that will print out messages so you know it hasn't locked up. - -The `yield_for()` method and `YIELD` constant are some syntax sugar built into the `Test` object. `yield` takes in an object and a signal. The `yield_for` method kicks off a timer inside Gut that will run for however many seconds you passed in. It also returns the Gut object so that `yield` has an object to yield to. The `YIELD` constant contains the name of the signal that Gut emits when the timer finishes. - -`yield_to` works similarly to `yield_for` except it takes the extra step that Gut will watch the signal you pass in. It will emit the same signal (`YIELD`) when it detects the signal you specified or it will emit the signal when the timer times out. +If you got here and weren't expecting to get here [let me know how you got](https://github.com/bitwes/Gut/issues) here so I can make getting here less likely in the future. \ No newline at end of file