RSpec 3 syntax is more verbose.
About twice as many characters to type to stub something:
obj.stub(client: client) # old
allow(obj).to receive(:client).and_return(client) # new
allow(obj).to receive(client: client) # possible? still much longer
allow(obj, client: client) # I might wrap it in thisMore characters to type for every single assertion (multiply by number of assertions desired):
obj.should == value
expect(obj).to eq value # +4 characters
obj.should_receive(:method)
expect(obj).to receive(:method) # +4 characters
expect(obj, eq value) # +2 characters and doesn't read as well# old frowned upon "its" extension, but look how few keystrokes, and how DRY
its(:body) { should include(text) }
# new (via transpec)
describe '#body' do
subject { super().body } # jon would disapprove of this anyway?
it { is_expected.to include(text) } # why is there one _ and one . (says my don't make me think brain)
end
its(:body) { is_expected.to include(text) }I think there are more examples too.
But you know, I don't so much mind the extra typing, it's probably having to type ( that bugs me. That character is significantly harder to type than . and ==.
Was the less metaprogramming, less magical solution worth it?
I have no easy solution to this by the way. Just trying to communicate something I expressed in 140 characters better.
Thanks for writing this up!
To respond to a few specific things you brought up:
This is possible with
allow(obj).to receive_messages(client: client). You can pass as many message/return value pairs as you want.I wouldn't say it's frowned upon. I have specs in some projects that use it. I'd say the abuse of it is frowned upon. I've actually gotten questions like "how do I test methods that take arguments?
itsdoesn't take any arguments"...to which I respond, "you write an example that calls the method with arguments;itswas never intended for that". From reading questions on stackoverflow, etc, I get the idea that some users believe the point of RSpec is to write tests in as terse a syntax as possible, and if there's not a one-liner syntax to support what they are trying to test, they feel like that's a deficiency in RSpec that should be addressed. That's not the point of RSpec at all. For an example like yours, I'd probably just test it like this:You say that your
itsexample is so DRY, but there is no duplication of knowledge in my version. It's not any less DRY. Your version is definitely fewer characters, but that has nothing to do with DRY.It's this way because
is_expectedis defined simply asexpect(subject)...sois_expected.tois the same asexpect(subject).to. That said, since it could trip people up, I've been mulling over addingis_expected_to,is_expected_to_notandis_expected_not_tojust so whatever users try works. (Kinda like how we supportexpect().to_notandexpect().not_to). Thoughts?I think so. Have you read my blog post about the new syntax and the reasons for its introduction? I myself experienced odd failures with proxy objects with the
shouldsyntax, and it took me like an hour to figure out, even though I was a contributor to RSpec!The new syntax is also much more consistent (and hopefully, easier to learn) than the old syntax. Consider that RSpec supports 3 kinds of expectations:
change,raise_error,throw_symboland yield matchers -- these are things that aren't static values and require blocks to test).Before introducing the new syntax, these three things had 3 different syntaxes:
These have now been nicely unified:
IMO, this consistency is a big win. I also think that this "wrapping" syntax makes it more explicit what RSpec's doing, which is a nice side effect.
But you're right -- these things are more verbose. Tradeoffs, as with all software engineering. I dislike excessive typing as much as anyone, but it's not RSpec's primary design goal to support tests being as terse as possible.
FWIW, we have no current plans to ever drop the old syntax (although, we may move it into an external gem in 4.0 -- that's not decided though), so if you prefer the old syntax and understand the tradeoffs, then keep using the old syntax. That's fine. Transpec even supports options to keep specific parts of the old syntax depending on what you want.
Anyhow, thanks again for engaging, and trying out RSpec 3!