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 verifying double features from rspec-fire. #378

Merged
merged 1 commit into from
Aug 6, 2013

Conversation

xaviershay
Copy link
Member

This is intended to be both API compatible with rspec-fire, and to completely obsolete it. It does not yet implement any of the suggested changes in #227, such as transferring nested constants by default or an alternate constant stubbing interface.

It adds the following behaviours:

verifying doubles
  class doubles
    when doubled class is not loaded
      allows any method to be stubbed
    when doubled class is loaded
      can transfer nested constants to the double
      can replace existing constants for the duration of the test
      only allows class methods that exist to be expected
      only allows class methods that exist to be stubbed
      allows class to be specified by constant
  instance doubles
    when doubled class is not loaded
      allows any instance method to be stubbed
    when doubled class is loaded
      only allows instance methods that exist to be expected
      only allows instance methods that exist to be stubbed
      checks the arity of stubbed methods
      allows class to be specified by constant
  when verify_constant_names config option is set
    prevents creation of instance doubles for unloaded constants
    prevents creation of class doubles for unloaded constants

It adds a perhaps unexpected method to the public API: ArityMatcher.match!. This seemed useful enough on its own to make public, but I would consider keeping it private if anyone exists.

Suggested reading order

If you are not familiar with rspec-fire, start with features/verifying_doubles/README.md. lib/rspec/mocks/example_methods.rb is the entry point for the feature. Trace that through until you find lib/rspec/mocks/verifying_proxy.rb which contains the bulk of the logic.

Questions for reviewers

  • I'm not familiar with yardoc style. Does this conform?
  • What is the preferred way to split features over the README and actual cucumber files?
  • It is unfortunate that I need to use a parallel class hierarchy for the verifying counterparts. Is there a better way to do this?

@myronmarston @JonRowe

Fixes #227.

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 42d0860 on xaviershay:issue-227 into e6d1980 on rspec:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 927ae29 on xaviershay:issue-227 into e6d1980 on rspec:master.

When using verifying doubles, RSpec will check that the methods being stubbed
are actually present on the underlying object if it is available.

No checking will happen when running the spec in isolation, but when run in the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the "when running the spec in isolation" part is a bit misleading: it's not about if I run rspec path/to/one/spec.rb vs rspec spec but about whether or not the named constant is loaded or not. I think of rspec path/to/one/spec.rb as "running a spec in isolation", but it will still verify the double if the named constant is loaded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

No checking will happen if the object definition isn't loaded, but when run with the object loaded (either as a full spec run or by explicitly preloading collaborators) a failure will be triggered if an invalid method is being stubbed.

@myronmarston
Copy link
Member

Looking good so far. I need to go fold laundry but I'll come back later (or perhaps tomorrow) to read through and comment on the rest.

@JonRowe
Copy link
Member

JonRowe commented Jul 24, 2013

Currently this is failing for all our 1.8.7 compatible builds.


# once you do this, you can no longer access MyCoolGem::Widget in your
# example...
class_double("MyCoolGem")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I the only one that finds class_double confusing when used on a Module? :)

@xaviershay
Copy link
Member Author

Thanks for the great feedback! Will address it all in the next couple of days.

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 9a8310c on xaviershay:issue-227 into e6d1980 on rspec:master.

@xaviershay
Copy link
Member Author

New commits are hiding an open discussion about naming of verify_constant_names option. Other suggestions (copied from old comments):

  • verify_instance_and_class_double_names
  • verify_verifying_double_names
  • check_verifying_double_names
  • verify_misspelled_constant_names
  • verify_doubled_constant_names
  • verify_doubled_class_names

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling b177ba4 on xaviershay:issue-227 into 474e643 on rspec:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 6ca3078 on xaviershay:issue-227 into 474e643 on rspec:master.

@xaviershay
Copy link
Member Author

1.8.7 is passing now.

@myronmarston
Copy link
Member

  • verify_instance_and_class_double_names

This is OK.

  • verify_verifying_double_names

I dislike. "verify verifying" is awkwardly awkward.

  • check_verifying_double_names

It's OK.

  • verify_misspelled_constant_names

It's OK.

  • verify_doubled_constant_names

I think I like this one best.

  • verify_doubled_class_names

I like this one OK, too.

method.name,
arity_description,
actual_arity
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason you prefer this over "#{string} #{interpolation}"? I find string interpolation easier to read.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(BTW, I'm not writing that to tell you you must change it--I'm genuinely curious why you chose to go that route!)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I find this version easier to read, since I see the "shape" of the sentence much clearer, and there's not so many that it isn't obvious which value interpolates where.
  2. It fits much nicer in 80-chars.

@@ -0,0 +1,52 @@
Feature: Using a class double

`class_double` is provided as a complement to `instance_double`, with the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this references instance_double, but comes first alphabetically, it would be good to list the order we want this in the relish nav file, so that this file can come later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in new commit.

@xaviershay
Copy link
Member Author

All other comments make sense, will revise.

underlying object if it is available. Prefer using veryifing doubles over
normal doubles.

No checking will happen if the object definition is not loaded, but when run
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No checking will happen if the object definition is not loaded

This is a bit misleading/inaccurate: it's not about whether or not the object definition is loaded, it's about whether or not the named class constant is defined. I've actually run into a subtle edge case where the class constant was defined but the object definition wasn't loaded, and rspec-fire told me the named class didn't implement a method that it actually did (at least it did when fully loaded). The specific edge case I ran into was in our use of a github-sourced gem in our gemfile that used the common idiom (as generated by bundle gem) whereby the .gemspec file has a require 'mygem/version', which caused MyGem::VERSION to get loaded (which implies that MyGem was a defined constant) when Bundler.setup ran (since it eval'd the gemspec file), but the actual definition of the MyGem class wasn't loaded. Note that this isn't a problem with normal released gems...the .gemspec file gets compiled to a static YAML file during that process, and thus bundler can read the gemspec w/o it loading the version constant.

While this is a bit of an edge case other users will hopefully never run into, I think it's good to reduce potential future confusion by accurately stating that the checking happens if the class constant is defined, regardless of whether or not the class definition is actually loaded.

@xaviershay
Copy link
Member Author

Don't have a strong opinion on the .name issue. I reckon let's role with current behaviour and if it trips anyone up we can revisit.

@myronmarston
Copy link
Member

As far as I'm concerned, this needs a changelog entry, and to be rebased against master (or merged against it, if you prefer), and it needs a green travis build, but is ready to be merged otherwise.

This is intended to be both API compatible with rspec-fire, and to
completely obsolete it.

Fixes rspec#227.
@xaviershay
Copy link
Member Author

@myronmarston rebased, Changelog entry added, CI is green.

@coveralls
Copy link

Coverage Status

Coverage increased (+0%) when pulling 03f51d9 on xaviershay:issue-227 into cee433c on rspec:master.

myronmarston added a commit that referenced this pull request Aug 6, 2013
Add verifying double features from rspec-fire.
@myronmarston myronmarston merged commit f9f0e5b into rspec:master Aug 6, 2013
@myronmarston
Copy link
Member

Beautiful :). Thanks for doing such a great job with this!

@myronmarston
Copy link
Member

BTW, I opened up issues for the other features and changes we discussed so that we don't forget them:

Do you want to take a stab at any of these, @xaviershay? If so, please comment on them so someone else doesn't also work on them and cause wasted effort.

@fables-tales
Copy link
Member

@xaviershay thanks so much, this is a really cool feature.

@soulcutter
Copy link
Member

@xaviershay I'm very excited about your work on this! Thanks a ton.

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

Successfully merging this pull request may close these issues.

stubs/expectations hide false positives
8 participants