Partial Doubles

A partial double is basically the inverse of a doubled object. It creates an object that acts exactly the same way as its source but has hooks that allows us to stub or spy on any method.

The partial_double method will create a partial double “class” which you can instance. You can partially double scripts, packed scenes, and inner classes. It works the same way as double works, so read up on that and then apply all that new knowledge to partial_double.

Under the covers, whether you call double or partial_double, GUT makes the same thing. If you call partial_double though, it will setup the object’s methods to be stubbed to_call_super instead of not being stubbed at all.

After you have your partial double, you can stub methods to return values instead of doing what they normally do. You can also spy on any of the methods.

NOTE As of 7.0.0, in an attempt to help tests create less orphans, all Doubles and Partial Doubles are freed when a test finishes. This means you do not have to free them manually and you should not use them in before_all.

Script Example

Given

# res://script.gd
extends Node2D

var _value = 10

func set_value(val):
  _value = val

func get_value():
  return _value

Then

func test_things():
  var partial = partial_double('res://script.gd').new()
  stub(partial, 'set_value').to_do_nothing()
  partial.set_value(20) # stubbed so implementation bypassed.

  # since set_value was stubbed, and get_value was not, and since
  # this is a partial stub, then the original functionality of
  # get_value will be executed and _value is returned.
  assert_eq(partial.get_value(), 10)
  # unstubbed partial methods can be spied on.
  assert_called(partial, 'get_value')
  # stubbed methods can be spied on as well
  assert_called(partial, 'set_value', [20])

Packed Scene Example

Given you have a scene res://scene.tscn that has the following script:

# res://script.gd
extends Node2D

var _value = 10

func set_value(val):
  _value = val

func get_value():
  return _value

Then

var partial = partial_double('res://scene.tscn').instance()
# or
var Scene = load('res://scene.tscn')
var partial = partial_double(Scene).instance()

Inner Class Example

# res://script.gd
extends Node2D

class InnerClass:
  var _value = 10

  func set_value(val):
    _value = val

  func get_value():
    return _value

Then

var partial = partial_double('res://script.gd', 'InnerClass').new()
# or
var Script = load('res://script.gd')
var partial = partial_double(Script, 'InnerClass').new()

Overriding Doubling Strategy

Partial doubles also support overriding the set Experimental Doubling Strategy. Pass in the strategy as an optional last parameter in any of the cases above. It will override the strategy used when creating just this one partial double Class.