Ajith
Ajith

Reputation: 345

rspec testing a class method giving object not spied or stubbed error

Rspec testing

I have class called Client.

class Client
  class << self
    def shutdown
      puts 'shutting down the producer gracefully'

      @producer ||= k_producer.producer(opts)
      @producer.shutdown
    end

    private
    def k_producer
      Kafka.new([127.0.0.1:9092], { required_acks: :all })
    end
  end
end

I want to test the shutdown class method and i do not understand the concept of stubbing or spy.

Im trying this way

RSpec.describe Client do
  describe "Client.shutdown" do
    it "calls shutdown" do
      described_class.shutdown
      expect(described_class).to have_received(:shutdown)
    end
  end
end

I'm getting this error where i do not know how to tell the rspec that i have @producer inside my class and shutdown is called on it.

Client (class)> expected to have received shutdown, but that object is not a spy or method has not been stubbed

Upvotes: 1

Views: 6571

Answers (1)

Schwern
Schwern

Reputation: 164819

You never set up described_class as a spy. You'd do this by making it a partial double with allow.

RSpec.describe Client do
  describe "Client.shutdown" do
    it "calls shutdown" do
      allow(described_class).to receive(:shutdown)
      described_class.shutdown
      expect(described_class).to have_received(:shutdown)
    end
  end
end

However, this test is tautological. You're simply testing that the test called Client.shutdown. It's more useful to test that @producer.shutdown is called.

It's a bit troublesome to get at @producer. We can make Client easier to test, and more flexible in general, by adding accessors for its internal objects.

class Client
  class << self
    # Define only the writers: producer= and kafka=
    attr_writer :producer, :kafka

    # Define the readers ourselves with our defaults.
    def producer
      @producer ||= kafka.producer(opts)
    end

    def kafka
      @kafka ||= Kafka.new(["127.0.0.1:9092"], { required_acks: :all })
    end

    def shutdown
      puts 'shutting down the producer gracefully'

      producer.shutdown
    end
  end
end

Now we make a spy and set it as the producer.

RSpec.describe Client do
  describe "Client.shutdown" do
    it "calls @producer.shutdown" do
      producer = spy("producer")
      described_class.producer = producer
      
      described_class.shutdown

      expect(producer).to have_received(:shutdown)
    end
  end
end

Upvotes: 5

Related Questions