icy-arctic-fox / spectator

Feature-rich testing framework for Crystal inspired by RSpec.
https://gitlab.com/arctic-fox/spectator
MIT License
103 stars 5 forks source link

Stubbed methods with default arguments not working #43

Closed simaoneves closed 2 years ago

simaoneves commented 2 years ago

It seems that default arguments are not working properly when the method in question is being stubbed.

require "spectator"

class Person
  def initialize(@dog = Dog.new)
  end

  def pet
    @dog.pet
  end
end

class Dog
  def initialize()
  end

  def pet(times = 3)
    "woof" * times
  end
end

Spectator.describe Person do
  mock Dog do
    stub pet(times)
  end

  describe "#pet" do
    it "pets the persons dog" do
      dog = Dog.new
      person = Person.new(dog)
      allow(dog).to receive(pet()).and_return("woof")

      result = person.pet

      expect(result).to be("woof")
      expect(dog).to have_received(pet())
    end
  end
end

The error is:

Screenshot 2022-02-23 at 17 48 05

Adding another stub to the mock (something like stub pet()) also does not work.

icy-arctic-fox commented 2 years ago

The current spec implementation requires that the stub signature matches the original method. It effectively replaces it, and if it doesn't match, then the stub doesn't work. Clunky and not the greatest, I plan to rework the stub system.

This works for me, can you confirm?

  mock Dog do
    stub pet(times = 3)
  end
simaoneves commented 2 years ago

The current spec implementation requires that the stub signature matches the original method. It effectively replaces it, and if it doesn't match, then the stub doesn't work. Clunky and not the greatest, I plan to rework the stub system.

This works for me, can you confirm?

  mock Dog do
    stub pet(times = 3)
  end

Wasn't aware that default arguments is effectively a new method signature, then it makes sense. Your suggestions fixes the example, but only for when you want to use the value in the default argument. Here is another example that uses a custom value and it fails:

require "spectator"

class Person
  def initialize(@dog = Dog.new)
  end

  def pet
    @dog.pet
  end

  def pet_more
    @dog.pet(5)
  end
end

class Dog
  def initialize()
  end

  def pet(times = 2)
    "woof" * times
  end
end

Spectator.describe Person do
  mock Dog do
    stub pet(times = 2)
  end

  describe "#pet" do
    it "pets the persons dog" do
      dog = Dog.new
      person = Person.new(dog)
      allow(dog).to receive(pet()).and_return("woof")

      result = person.pet

      expect(dog).to have_received(pet()).with(2)
    end
  end

  describe "#pet_more" do
    it "pets the persons dog alot" do
      dog = Dog.new
      person = Person.new(dog)
      allow(dog).to receive(pet()).and_return("woof")

      result = person.pet_more

      expect(dog).to have_received(pet()).with(5)
    end
  end
end

Thanks for looking into this 😄

icy-arctic-fox commented 2 years ago

This issue should be resolved in v0.11.0. There is a spec dedicated to it. Please reopen if your issue is not resolved.