Reputation: 111
So this is a brief tutorial I found abouot Rspec: w3ii.com: rspec on it's explanation about rspec helpers. This is the code for the example:
class Dog
attr_reader :good_dog, :has_been_walked
def initialize(good_or_not)
@good_dog = good_or_not
@has_been_walked = false
end
def walk_dog
@has_been_walked = true
end
end
describe Dog do
def create_and_walk_dog(good_or_bad)
Dog.new(good_or_bad).walk_dog
end
it 'should be able to create and walk a good dog' do
dog = create_and_walk_dog(true)
expect(dog.good_dog).to be true
expect(dog.has_been_walked).to be true
end
end
When I run this, I get this error:
NoMethodError: undefined method 'good_dog' for true:TrueClass
# ./dor.rb:22:in 'block <2 levels> in >'
I can't understand how a call to Dog.new() returns a true:TrueClass object instead of a simple dog.
Upvotes: 4
Views: 259
Reputation: 444
I think for clarity you could/should be using the RSpec let method here not a full method definition included in your RSpec file. Having your _walk_dog_ method return self like suggested on another answer I see here fixes your current RSpec implementation but does not help your flow anywhere else in your potential application. Hypothetical case where bad dogs return false for _dog.walk_dog_ randomly 50% of the time or just not cooperate at all.
class Dog
attr_reader :good_dog, :has_been_walked
def initialize(good_or_not)
@good_dog = good_or_not
@has_been_walked = false
end
# Command to attempt walking a dog.
#
# @api public
#
# @example
# good_dog = Dog.new(true)
# good_dog.walk_dog # => Will always return true for good dogs.
# bad_dog = Dog.new(false)
# bad_dog.wal_dog # => 50/50 chance of true or false
def walk_dog
return @has_been_walked = true if @good_dog
[true, false].sample
end
end
describe Dog do
let(:good_dog) { Dog.new(true) }
it 'should always be able to walk a good dog' do
expect(good_dog.walk_dog).to be true
end
it 'should track if the dog has been walked' do
expect {
good_dog.walk_dog
}.to change(dog, :has_been_walked).from(false).to true
end
end
Up for debate also but you should only be asserting a single thing per spec also unless you are hitting the db or doing something relatively time consuming.
P.S. They are all good dogs Brent
Upvotes: 0
Reputation: 15045
That's because the create_and_walk_dog
returns that the walk_dog
method returns
To return a dog from the create_and_walk_dog
method you'll need something like
describe Dog do
def create_and_walk_dog(good_or_bad)
dog = Dog.new(good_or_bad)
dog.walk_dog
dog
end
it 'should be able to create and walk a good dog' do
dog = create_and_walk_dog(true)
expect(dog.good_dog).to be true
expect(dog.has_been_walked).to be true
end
end
Or extend the expectation block:
describe Dog do
it 'should be able to create and walk a good dog' do
dog = Dog.new(true)
expect(dog.good_dog).to be true
expect {
dog.walk_dog
}.to change(dog, :has_been_walked).from(false).to true
end
end
Upvotes: 3