I am currently trying to create a test for the below code. I wrote the test first and then wrote the code and realised my test is not doing what I want it to do.
class Weather
def initialize
@weather = 'sunny'
end
def weather_randomiser
case rand(1..10)
when 1..8 then @weather = 'sunny'
when 9..10 then @weather = 'stormy'
end
end
def stormy?
weather_randomiser
@weather == 'stormy'
end
end
My test is as follows:
require 'weather.rb'
describe Weather do
it 'randomises weather and sets the weather to the randomised result' do
weather = Weather.new
allow(weather).to receive(:weather_randomiser).and_return(9)
expect(weather).to be_stormy
allow(weather).to receive(:weather_randomiser).and_return(2)
expect(weather).to_not be_stormy
end
end
Can you please explain how I go about testing the weather_randomiser and stormy? methods similar to this/ is it possible with my code.
Further could you explain how you got to where you did as I would like to understand not just have an answer.
Thank you very much in advance :)
CodePudding user response:
I believe you can use the following snippet. Here you want to stub the rand
function itself. I really don't recommend that. I would recommend if you have your class that may be called Randomizer
and it contains the random
class. Stubbing classes like Object
is not good at all.
#!/usr/bin/env ruby
require_relative '../weather.rb'
RSpec.describe Weather do
it 'randomises weather return stormy' do
allow_any_instance_of(Object).to receive(:rand).and_return(9)
weather = Weather.new
expect(weather).to be_stormy
end
it 'randomises weather return sunny' do
allow_any_instance_of(Object).to receive(:rand).and_return(4)
weather = Weather.new
expect(weather).to_not be_stormy
end
end
CodePudding user response:
Your weather_randomiser
does too many things:
- It generates a random number
- It maps a random number to a string value
- It updates an instance variable
To make things more testable, you could split those out, e.g.:
def weather_randomiser
rand(1..10)
end
def set_weather(value)
@weather = case value
when 1..8 then @weather = 'sunny'
when 9..10 then @weather = 'stormy'
end
end
def stormy?
set_weather weather_randomiser
@weather == 'stormy'
end
It does introduce an awkward coupling between the randomiser and setter; changing the former requires looking at the latter ... ymmv