Home > Blockchain >  RSpec how to mock a ZendeskAPI::Collection object?
RSpec how to mock a ZendeskAPI::Collection object?

Time:07-08

I'm trying to mock a zendesk API response that's called like this:

zendesk_client = ZendeskHelper.make_client
tickets = zendesk_client.search.export(query)

The application iterates through all the pages in a Zendesk API request using the API's .all! method:

tickets.all! do |ticket|
  # do something
end

Initially, I put some doubles in an array and used that as a mock response:

mock_tickets = [
  double('ticket'),
  double('ticket'),
  double('ticket')
]

allow(mock_zendesk_client).to receive_message_chain(:search, :export).and_return(mock_tickets)

But I get a syntax error because a normal array cannot use the .all! method.

I inspected the real tickets response, and it was a ZendeskAPI::Collection object. How can I mock this object so my mock response can use the .all! method?

The .all! method looks like this

def all!(start_page = @options["page"], &block)
  _all(start_page, :bang, &block)
end

...

def _all(start_page = @options["page"], bang = false, &block)
  raise(ArgumentError, "must pass a block") unless block

  page(start_page)
  clear_cache

  while (bang ? fetch! : fetch)
    each do |resource|
      arguments = [resource, @options["page"] || 1]

      if block.arity >= 0
        arguments = arguments.take(block.arity)
      end

      block.call(*arguments)
    end

    last_page? ? break : self.next
  end

  page(nil)
  clear_cache
end

CodePudding user response:

Usually when you get into a situation like you're in trying to deep-mock some third party's API response, you'll find that you're actually testing the third party's API, not your own code.

You should have a layer above the Zendesk response that's full of objects YOUR code is creating, mock THERE instead.

CodePudding user response:

Got a suggestion from a senior dev, the solution is to mock the implementation of .all!.

mock_items = [double('mock_item')]
mock_response = double('mock_response',
  # need to have `all!` here, else you'll get error saying the double doesn't implement `.all!`
  all!: ''
)

allow(mock_response).to receive(:all) do |&block|
  # iterates through the items using the block that follows .all!
  mock_items.each do |item|
    block.call(item)
  end
end
  • Related