bradley plater
bradley plater

Reputation: 1273

Testing in Rspec a random weather methods functionality depending on the random number generated

I am trying to have 2 tests to check the functionality of a method within the Weather class. The random_weather method should change @status depending on the result of random_number. However I cannot find a way to force random_number to be a certain number.

RSpec test:

require 'weather'

describe Weather do
  subject { Weather.new }

  it 'Can create an instance of Weather' do
    expect(subject).to be_instance_of Weather
  end

  it 'Can return sunny when randomly choosing weather' do
    subject.stub(:generate_random_number) {5}
    expect(subject.status).to eq "Sunny"
  end

  it 'Can return stormy when randomly choosing weather' do
    subject.stub(:generate_random_number) {9}
    expect(subject.status).to eq "Stormy"
  end
end

Weather Class:

class Weather
  attr_reader :status, :random_number

  def initialize
    @random_number = generate_random_number
    puts @random_number
    if (1..8).include?(@random_number)
      @status = "Sunny"
    else
      @status = "Stormy"
    end
  end

  def generate_random_number
    rand(1..10)
  end
end

example failure:

  1) Weather Can return stormy when randomly choosing weather
     Failure/Error: expect(subject.status).to eq "Stormy"

       expected: "Stormy"
            got: "Sunny"

       (compared using ==)
     # ./spec/weather_spec.rb:17:in `block (2 levels) in <top (required)>'

Upvotes: 0

Views: 316

Answers (1)

mrzasa
mrzasa

Reputation: 23317

You have 3 options:

  • wrap randomness in a method and stub this method
  • wrap or a generator class that is injected, and inject a non-random generator in spec
  • stub rand

I prefer the second option, but the first one may be enough.

Private method

class Weather
  attr_reader :status, :random_number

  def random_weather
    @random_number = generate_random_number
    # ...
  end

  def generate_random_number
    rand(1..10)
  end
end

#specs
  it 'Can return sunny when randomly choosing weather' do
    subject.stub(:generate_random_number) {5}
    expect(subject.status).to eq "Sunny"
  end

Generator injection

class Weather
  attr_reader :status, :random_number
  def initialize(random_number_generator: RandomNumberGenerator)
    @random_number_generator = random_number_generator
  end

  def random_weather
    @random_number = random_number_generator.call
    # ...
  end
end

class RandomNumberGenerator
  def self.call
    rand(1..10)
  end
end

#specs
  subject { described_class.new(generator) }
  let(:generator) { ->{ 5 } }    
  it 'Can return sunny when randomly choosing weather' do
    expect(subject.status).to eq "Sunny"
  end

Stubbing rand in specs

  it 'Can return sunny when randomly choosing weather' do
    stub(:rand) {5}
    expect(subject.status).to eq "Sunny"
  end

Upvotes: 2

Related Questions