Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add some means to assert that a stub was called #434

Open
geemus opened this issue Oct 20, 2014 · 6 comments
Open

add some means to assert that a stub was called #434

geemus opened this issue Oct 20, 2014 · 6 comments
Labels

Comments

@geemus
Copy link
Contributor

geemus commented Oct 20, 2014

No description provided.

@geemus
Copy link
Contributor Author

geemus commented Oct 22, 2014

/cc @jkakar I know you have brought this up a couple times. Could you summarize what you have in mind and/or hook me up with a couple links to where you rolled your own? I'd like to do something here, but want to have a little better sense of the design goal before I get too far in to it. Thanks!

@jkakar
Copy link

jkakar commented Oct 22, 2014

Fundamentally, when I ask Excon to stub a request I expect it to blow
up if that request is never made. Stubbed requests that are never
invoked are silently ignored at present. I consider this a bug
because it's too easy for tests to spuriously pass when, in fact, none
of the assertions in the stubbed request block were ever run. To work
around that I pop stubbed requests out of Excon.stubs when they're
called and assert that all stubbed requests have been called when a
test ends.

I include this test helper in tests that mock Excon:

module ExconHelper
  def setup
    super
    Excon.stubs.clear
    Excon.defaults[:mock] = true
  end

  def teardown
    # FIXME This is a bit ugly, but Excon doesn't provide a builtin way to
    # ensure that a request was invoked, so we have to do it ourselves.
    # Without this, and the Excon.stubs.pop calls in the tests that use this
    # helper, tests will pass if request logic is completely removed from
    # application code. -jkakar
    assert(Excon.stubs.empty?, 'Expected HTTP requests were not made.')
    super
  end
end

I explicitly pop the stubbed request out of the Excon.stubs array in
the stubbed request block so that the check for Excon.stubs.empty?
in ExconHelper.teardown works correctly:

class LinkTest < MiniTest::Unit::TestCase
  include ExconHelper

  # Link.run invokes a request against the service identified by the URL.  The
  # path is left unchanged when parameters aren't required and the username
  # and password from the URL are passed using HTTP basic auth.
  def test_run_without_parameters_and_with_empty_response
    Excon.stub(method: :get) do |request|
      assert_equal('Basic dXNlcm5hbWU6c2VjcmV0',
                   request[:headers]['Authorization'])
      assert_equal('example.com', request[:host])
      assert_equal(443, request[:port])
      assert_equal('/resource', request[:path])
      Excon.stubs.pop
      {status: 200, body: ''}
    end

    schema = Heroics::Schema.new(SAMPLE_SCHEMA)
    link = Heroics::Link.new('https://username:secret@example.com',
                             schema.resource('resource').link('list'))
    assert_equal(nil, link.run)
  end
end

It's a bit ugly but it ensures that the tests are reliable.

@geemus
Copy link
Contributor Author

geemus commented Oct 28, 2014

@jkakar awesome, thanks for the context. Moving past the current, unfortunate state, thoughts on what invocation might look like in an idealized future?

@jkakar
Copy link

jkakar commented Oct 28, 2014

I like the API Excon provides for stubbing calls. It's simple and
intuitive. I think adding an Excon.verify_stubs call that can be
invoked in teardown to ensure that all stubbed requests were called
would be nice. If you want to make it a bit easier to consume you
could go the route of RR, for example, and provide builtin
integrations
for popular test frameworks.

@geemus
Copy link
Contributor Author

geemus commented Oct 28, 2014

Good call. I'll probably start with something like #verify_stubs (when I get a chance) and work from there. Do you think boolean is good-enough? ie I've seen some tests where it would be something like called-only-once or called-twice or something. Just trying to figure out internally how to represent this. Maybe a hash of stub to count of calls (and verify would be true as long as all calls are > 1. Not sure I'd reveal the called-x-times stuff right away, but seems like it might be useful eventually and wouldn't be much different/harder than boolean I think/hope.

@stale
Copy link

stale bot commented Jul 30, 2018

This issue has been automatically marked stale due to inactivity. It will be closed if no further activity occurs. Thank you for your contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants