jimweirich / rspec-given

Given/When/Then keywords for RSpec Specifications
https://github.com/jimweirich/rspec-given
MIT License
653 stars 61 forks source link

Using Then within iteration does not show useful info in document or HTML format, unlike it() #14

Closed scrapcupcake closed 11 years ago

scrapcupcake commented 11 years ago

describe "thing" do let(:subject){ "abcde" } %w(a b c d e).each do |thing| it "matches thing #{thing}" do subject.should include thing end Then { subject.should include thing } end end

Output: thing matches thing a Then { subject.should include thing } matches thing b Then { subject.should include thing } matches thing c Then { subject.should include thing } matches thing d Then { subject.should include thing } matches thing e Then { subject.should include thing }

I came across this when trying to use rspec-given in a shared example and wanted to be able to iterate through a fairly complex set of tests I have set up, and boiled my issue down to the above. The rest of my tests use rspec-given, so it would have been nice to keep the output consistent, but for now I'll have to revert to it(). I'm happy to put some work into getting this fixed, but I won't have time for a while yet, so I thought I'd post this here in case anyone else runs across this.

jimweirich commented 11 years ago

I think the key to using Then effectively is to write the code to be so expressive you don't miss having a comment. There are several solutions to your particular issues. Here's some ideas:

(1) Write a matcher that works on your list %w(a b c d e) and puts it all in a single then:

  matcher :all_be_included_in do |sub|
    match do |includes|
      includes.all? { |x| sub.include?(x) }
    end
  end

  Then { %w(a b c d e).should all_be_included_in subject }

You can even beef up the matcher to pin-point which item is not being included when a failure occurs.

(2) If the literal for the list of things to be included is too big for easy readability, then name it and use the name:

  Given(:first_five_letters) { %w(a b c d e) }
  Then { first_five_letters.should all_be_included_in subject }

(3) Write a small function to check for inclusion

  def all_included_in?(sub, others)
    others.all? { |x| sub.include?(x) }
  end

  Given(:first_five_letters) { %w(a b c d e) }
  Then { all_included_in? subject, first_five_letters }

If none of these appeal to you, then just using the 'it' block with a descriptive string is still a valid way to go.

Note: Here is a gist where I explore the above ideas (and several others): https://gist.github.com/4666180

hoguej commented 11 years ago

I found this useful for another similar question. Wonder if it should work it's way into the main documentation.

When I ask people to use this lib, this is the first question I get that I haven't had a good answer for until now.