Testing ARGV options with rspec. How to expect a method to call a method from another module

Viewed 357

I am building a CLI in Ruby and I am using ARGV to pass options and arguments in the command line. I have a call method that is triggered when the CLI is executed. The call method is as follows:

module Eltiempo
  class CLI
    def call
      help_menu if ARGV.count.zero?
      case ARGV[0]
      when '-today'
        raise NoCityError if ARGV[1].nil?

        Eltiempo.today(ARGV[1])
      when '-av_min'
        raise NoCityError if ARGV[1].nil?

        Eltiempo.av_min(ARGV[1])
      when '-av_max'
        raise NoCityError if ARGV[1].nil?

        Eltiempo.av_max(ARGV[1])
      when '-h'
        help_menu
      end
    end

When doing the test with rspec for the first case option (-today) I have written the following code:

RSpec.describe Eltiempo do
  describe '#call' do
    context 'given -today' do
      let(:ARGV) { ['-today', 'Barcelona'] }
      it 'calls function to return today\'s weather' do
        expect(Eltiempo::CLI.new.call).to receive(Eltiempo.today).with(ARGV[1])
      end
    end
  end
end

However, when running rspec it is not passing the test and it says:

Failure/Error:
       def self.today(city_name)
         max = max_today(city_name)
         min = min_today(city_name)
         puts "Weather today in #{city_name.capitalize}:
           - Maximum: #{max}°C
           - Minimum: #{min}°C"
       end
     
     ArgumentError:
       wrong number of arguments (given 0, expected 1)

It is trying to call the method self.today(city_name) in Eltiempo module and to run in without the city_name argument, however, I do not want it to run the method I just want to check that when the option and argument -today Barcelona is run, it calls Eltiempo.today(ARGV[1]).

Why is it running self.today(city_name)?

1 Answers

The method call is coming from inside the house!

expect(Eltiempo::CLI.new.call).to receive(Eltiempo.today).with(ARGV[1])
                                          ^^^^^^^^^^^^^^

That is just what it looks like, a call to Eltiempo.today with no arguments.

Setting up an expectation says you expect a particular object to receive a certain method. This object in this case is the class Eltiempo. The method is passed by name as a Symbol. After the expectation that today will be called on Eltiempo is set up, then you run the code which is expected to call Eltiempo.today

expect(Eltiempo).to receive(:today).with(ARGV[1])
Eltiempo::CLI.new.call

RSpec has replaced the method today on Eltiempo with one that records whether it's been called and returns nothing.

Related