-
-
Notifications
You must be signed in to change notification settings - Fork 359
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
Diff the arguments passed to expectations on failure, similar to how matchers do #434
Comments
I can see how this would work, but we'd have to pull the differ from |
At one point we talked about pulling the differ out into it's own gem, and allowing people to pick the differ they wanted, in which case we wouldn't want to support it |
I've got branches of rspec-expectations and rspec-support where I've attempted to extract the diffing code into support: https://github.com/phiggins/rspec-expectations/tree/extract-differ-to-support It's a bit rough and doesn't have all the complexities worked out, but I thought I'd request some feedback before I put too much more time into it. |
@phiggins: this general direction looks great. I had this slated for post 3.0 (e.g. 3.1 or whatever) but that's mostly a function of the limited time of the core team. Getting a contribution from a user like yourself for this is great! |
Looks like a good start! Let us know when you want a proper review :) |
One thing to be aware of is changes to the |
Thanks for the heads up @myronmarston! |
I have a few general questions that you guys could help me with. Some of the specs in RSpec projects use nested modules around the describe calls while others include the nesting in the describe call. Is there a preference project wide, or does it depend on the context? I generally prefer the latter and would use that if there's no preference, but I'm happy to do some cleanups if there's strong preferences either way. DiffPresenter has two explicit dependencies on rspec-expectations: RSpec::Matchers.configuration.color? and RSpec::Matchers::Composable.surface_descriptions_in(object). I thought I'd make this more reusable by changing the way DiffPresenter is created to something like this: # in rspec-expectations
DiffPresenter.new(
:color? => RSpec::Matchers.configuration.color?,
:stringifier => lambda {|obj| RSpec::Matchers::Composable.surface_descriptions_in(obj) }
)
# in rspec-support
module RSpec
module Support
class DiffPresenter
def initialize(opts)
@color = opts.fetch(:color?, false)
@stringifier = opts.fetch(:stringifier) { lambda {|obj| obj } }
end
end
end
end Does this seem like a good way to go? I'm not crazy about the name |
Personally I favour the latter but the former is more common. I'm happy for either usage tbh. As regards to naming I'm in favour of your proposed names. |
I prefer the former, as it allows you to reference constants without needing to fully qualify them. I think the majority of rspec's specs are written in this style. It's not a big deal either way, though. Re: config The |
To maintain the idea that rspec-expectations and rspec-mocks are self-contained modules that can be used outside of rspec, I think it makes sense for both of them to defer to RSpec's configuration but provide their own in case that doesn't exist. It does create a bit of duplication, but I'm not sure how, for example, rspec-mocks used outside of rspec would expose the color setting if it was only implemented in rspec-support. |
The approach I was trying to make by passing in a |
I'm ok with a minor bit of duplication on the configuration objects, then having each gem use that to configure the differ. There might be some scope for support having a "config" decider though... |
Outside the scope of this PR, but it might be cool to move the configuration object into support as well, then have expectations and mocks each try to reuse RSpec's configuration instance, creating their own if that doesn't exist. |
Yep. |
Off topic again but if we do anything with config I think we could move the core "how configuration is made" logic to support, and then define the keys supported by each gem in their own config classes, as although it's a minor bit of duplication it better shows the intent of the config in each gem. |
Related #434. This uses the differ that is now in RSpec support to perform argument diffing when arguments don't match. Things worth noting/still to do: * Special case behaviour needs to be added for the no arguments matcher and the any arguments matcher, at the moment something like this: @@ -1,2 +1,2 @@ -[#<RSpec::Mocks::ArgumentMatchers::NoArgsMatcher:0x000001024ec728>] +[{:bees=>:foo}] gets printed, and that's obviously not great. * Need to work out what to do in the "similar args" case where there are potientially multiple calls. I think the best thing to do would be to would be to only diff if there's one call. There's some refactoring that could be done here but I want to finish implementing the "similar args" implementation before I do that so that I'm sure that I'm refactoring the right thing.
Related #434. This uses the differ that is now in RSpec support to perform argument diffing when arguments don't match. Things worth noting/still to do: * Special case behaviour needs to be added for the no arguments matcher and the any arguments matcher, at the moment something like this: @@ -1,2 +1,2 @@ -[#<RSpec::Mocks::ArgumentMatchers::NoArgsMatcher:0x000001024ec728>] +[{:bees=>:foo}] gets printed, and that's obviously not great. * Need to work out what to do in the "similar args" case where there are potientially multiple calls. I think the best thing to do would be to would be to only diff if there's one call. There's some refactoring that could be done here but I want to finish implementing the "similar args" implementation before I do that so that I'm sure that I'm refactoring the right thing.
Related #434. This uses the differ that is now in RSpec support to perform argument diffing when arguments don't match. Things worth noting/still to do: * Special case behaviour needs to be added for the no arguments matcher and the any arguments matcher, at the moment something like this: @@ -1,2 +1,2 @@ -[#<RSpec::Mocks::ArgumentMatchers::NoArgsMatcher:0x000001024ec728>] +[{:bees=>:foo}] gets printed, and that's obviously not great. * Need to work out what to do in the "similar args" case where there are potientially multiple calls. I think the best thing to do would be to would be to only diff if there's one call. There's some refactoring that could be done here but I want to finish implementing the "similar args" implementation before I do that so that I'm sure that I'm refactoring the right thing.
Closing because of #751 |
Recently I've had the idea that it would be useful if the arguments expected by the mocks set up with
expect().to receive
and friends were diffed similarly to how the arguments passed to matchers are.Here's a short example of what I mean:
When run, I see output like this:
It is much easier to spot the difference in the error message of the second test than it is in the first. This would come in handy when doing things like testing that the arguments passed to a collaborator are filtered or modified in a certain way. I've wanted this functionality for testing things like knowing that an object receives a certain subset of parameters passed as query arguments to a rails controller, for example.
I took a look at what it would take to either reimplement or share the code for the diffing stuff in rspec-expectations, and it seems very specific to implementing the error messages of the matchers. I'd be willing to take a crack at a patch for this if it's deemed a worthy addition and there was some guidance for how to proceed.
The text was updated successfully, but these errors were encountered: