Rspec issue on 'Methods Exercises'

Having an issue passing the final test.

Failures:

  1. methods.rb int_remainder_without_modulo doesn’t use the % operator
    Failure/Error: i_dividend - ((i_dividend / i_divisor) * i_divisor)
    #<Double “Integer”> received unexpected message :- with (2)

    ./lib/methods.rb:106:in `int_remainder_without_modulo’

    ./spec/methods_spec.rb:144:in `block (3 levels) in <top (required)>’

Finished in 0.01033 seconds (files took 0.06687 seconds to load)
27 examples, 1 failure

Failed examples:

rspec ./spec/methods_spec.rb:141 # methods.rb int_remainder_without_modulo doesn’t use the % operator

Here’s my code:

def int_remainder_without_modulo(i_dividend, i_divisor)
i_dividend - ((i_dividend / i_divisor) * i_divisor)
end

And the rspec:

describe “int_remainder_without_modulo” do
it “knows 8 mod 3 is 2” do
expect(int_remainder_without_modulo(8, 3)).to be(2)
end

it "knows 5 mod 6 is 5" do
  expect(int_remainder_without_modulo(5, 6)).to eq(5)
end

it "doesn't use the % operator" do
  a = double("Integer", :/ => 1, :to_f => 2.0)
  expect(a).not_to receive(:%)
  int_remainder_without_modulo(a, 2)
end

end

I tried a couple different solutions, and kept getting the same issue. Thx!

1 Like

Hi Ravi,

Awesome job, this is not an error with your code, but with the specs themselves. While in the App Academy main course you will learn all about RSPEC and how to read more complicated error messages such as this one. For now, let’s talk about this case as a learning lesson and I will update the project for the future.

Problem: When writing specs, the more different objects we use, the wider our range for errors.

Example: If we are testing a modulo method using an Integer class then our tests will fail if the modulo method is written incorrectly OR if there is an error in the Integer class itself!

Solution: We should be as targeted with our tests as possible and use “pretend” objects instead of the real ones.

Explanation: In RSPEC we call these “pretend objects” mocks or doubles. By “mocking” objects such as the Integer class, we avoid any issues with the class that may cause a false-negative in our test cases.

a = double("Integer", :/ => 1, :to_f => 2.0)

The hash options being passed after the name of the class to mock represents another concept called method stubs. In order to call methods on our “pretend objects” we create fake ones that return exactly what we tell them to. This mock object of an Integer has the / method and the to_f method which return 1 and 2.0 respectively.

This brings us to the error message:

Failure/Error: i_dividend - ((i_dividend / i_divisor) * i_divisor)
# received unexpected message :- with (2)

If we follow the test with your code we will see that the number 2 receives the - method and this is not one of the methods we “stubbed” out on our mock Integer object. Hence the error.

Refactor: We can either add a hash option for the :- method just like the :/ method or we can use a handy method from rspec so that we don’t have to worry about stubbing out all the methods we want. This method is called as_null_object.

The specs will be updated as follows:

it "doesn't use the % operator" do
  a = double('Integer').as_null_object
  expect(a).not_to receive(:%)
  int_remainder_without_modulo(a, 2)
end

Let mw know if you have any questions and thanks again for the awesome question!

2 Likes

Hello, I actually have the same problem. I got the same solution that Ravi got and I’m getting the same error. When I change the RSPEC code to
it "doesn't use the % operator" do a = double('Integer').as_null_object expect(a).not_to receive(:%) int_remainder_without_modulo(a, 2) end

I get the following error
TypeError: coerce must return [x, y]

Should I just leave the RSPEC code as is, or change it in some other way?

Thanks,

David

Thanks for this explanation. I ran into the same problem but was able to resolve it after changing the RSpec test. Two questions…1) Why do you have to set return values for the stub methods and what is the significance of the return values? 2) When would you use stubs instead of as_null_object?

Return values can help when we are expecting for something to be returned instead of just expecting for a method to be called. This is also why we would want to stub instead of using as_null_object.

For example, let’s say I had a user and I wanted to test the name? method that checks if they have a name. Users are complicated objects with all sorts of methods so to narrow down our test we could mock the user, stub the name method and make it return “Kevin.” Now when I look for a name inside the name? method it will automatically return “Kevin” and I don’t have to worry about anything else like if the user was created correctly with their email/password, etc.

The takeaway here is that we are trying to eliminate all the variables and just test one thing at a time. Hopefully that example was not too confusing, you will learn much more RSPEC in the immersive course. Let me know if you have any questions! :nerd_face:

Hi Kevin,

I ran into the same error today. Should we change the spec here (based on your update above) before submitting the assignment?

Screenshot%20from%202018-07-02%2006-01-12

My solution

def int_remainder_without_modulo(i_dividend, i_divisor)
temp = i_divisor * dec_remainder_of_two_integers(i_dividend, i_divisor)
ans = temp.round.to_i
end

I also ran into the same problem and based on the thread above I changed the test (line 141) in methods_spec.rb to the following:

it “doesn’t use the % operator” do
a = double(‘Integer’, :confused: => 1, :to_f => 2.0).as_null_object
expect(a).not_to receive(:%)
int_remainder_without_modulo(a, 2)
end

Adding , :confused: => 1, :to_f => 2.0 after ‘Integer’ seemed to fix the problem as the test then passed. Should I submit my work with this changed test?

:confused: should be colon forward slash(:/)

Hi, I was running into the same situation. First I will tell you the 2 things that I tried that did not work because they should have worked according to the error given and the description

This is the code I written in the beginning

def dec_remainder_of_two_floats(f_dividend, f_divisor)
    ( f_dividend / f_divisor ) % 1
end

def dec_remainder_of_two_integers(i_dividend, i_divisor)
    dec_remainder_of_two_floats(i_dividend.to_f, i_divisor.to_f)
end

def int_remainder_without_modulo(i_dividend, i_divisor)
    (dec_remainder_of_two_integers(i_dividend, i_divisor) * i_divisor).round
end

This didn’t work because as you can see int_remainder_without_modulo depends on the method two above it (dec_reaminder_of_two_floats). So I re-wrote my code to use no helper methods like this.

def int_remainder_without_modulo(i_dividend, i_divisor)
    # (dec_remainder_of_two_integers(i_dividend, i_divisor) * i_divisor).round
    num_times = (i_dividend / i_divisor).floor
    i_dividend - (i_divisor * num_times)
end

This didn’t work because it didn’t use dec_remainder_of_two_integers as a helper method. So, as you can probably tell, the only way I passed the test was by not using any % (modulo) in any of the helper methods and also using dec_remainder_of_two_integers as a helper method.

I hope this helps

Aloha,
Steve – CoHort SF Oct 22, '18