Are There Any Good Mutation Testing Tools for Ruby 1.9 and Rspec2

Rspec: expect vs expect with block - what's the difference?

As has been mentioned:

expect(4).to eq(4)

This is specifically testing the value that you've sent in as the parameter to the method. When you're trying to test for raised errors when you do the same thing:

expect(raise "fail!").to raise_error

Your argument is evaluated immediately and that exception will be thrown and your test will blow up right there.

However, when you use a block (and this is basic ruby), the block contents isn't executed immediately - it's execution is determined by the method you're calling (in this case, the expect method handles when to execute your block):

expect{raise "fail!"}.to raise_error

We can look at an example method that might handle this behavior:

def expect(val=nil)
if block_given?
begin
yield
rescue
puts "Your block raised an error!"
end
else
puts "The value under test is #{val}"
end
end

You can see here that it's the expect method that is manually rescuing your error so that it can test whether or not errors are raised, etc. yield is a ruby method's way of executing whatever block was passed to the method.

RSpec can't define singleton error when trying to mock gets and puts for Hash Elements

If you run the spec with the --backtrace flag, you'll see that the error is raised on https://github.com/rspec/rspec-mocks/blob/v2.13.0/lib/rspec/mocks/method_double.rb#L140, where rspec-mocks is trying to get the singleton class of the object being stubbed or mocked. This would work fine with instances of most classes, but there is an error in the spec.

The code sends gets to STDIN, but the spec is trying to stub gets on book_obj.books["The Last Samurai"], which is an int at the time, and you can't get a singleton from an int:

$ irb
1.9.3-p392 :001 > class << 1; self; end
TypeError: can't define singleton
from (irb):1
from /Users/david/.rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in `<main>'

If I understand correctly, you want to make two changes. First, move the last lines of the script to a separate file that doesn't get loaded when you run the spec e.g. bin/books (it can require book.rb and then add those lines).

Next, remove the line that stubs gets on book_obj.books["The Last Samurai"] and add a line that stubs gets on STDIN instead, before the line that invokes get_prices (which is when the interaction w/ STDIN happens):

STDIN.stub(:gets) { "40" }
book_obj.get_prices.should_not be_nil

That will at least get your spec passing.

In general, code that deals w/ STDIN and STDOUT directly is hard to spec at the object level because testing tools like rspec, minitest, etc, all use STDOUT to present their information, so you end up with a lot of confusing noise in the shell. I'd recommend either changing the design to inject input/output streams to the book class (which can be STDIN and STDOUT when you run the script, but test doubles when you run rspec), or use a tool like aruba, which is designed to spec interactive shell scripts.

Rspec: expect vs expect with block - what's the difference?

As has been mentioned:

expect(4).to eq(4)

This is specifically testing the value that you've sent in as the parameter to the method. When you're trying to test for raised errors when you do the same thing:

expect(raise "fail!").to raise_error

Your argument is evaluated immediately and that exception will be thrown and your test will blow up right there.

However, when you use a block (and this is basic ruby), the block contents isn't executed immediately - it's execution is determined by the method you're calling (in this case, the expect method handles when to execute your block):

expect{raise "fail!"}.to raise_error

We can look at an example method that might handle this behavior:

def expect(val=nil)
if block_given?
begin
yield
rescue
puts "Your block raised an error!"
end
else
puts "The value under test is #{val}"
end
end

You can see here that it's the expect method that is manually rescuing your error so that it can test whether or not errors are raised, etc. yield is a ruby method's way of executing whatever block was passed to the method.



Related Topics



Leave a reply



Submit