Skip to content

Instantly share code, notes, and snippets.

@cupakromer
Last active January 2, 2016 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cupakromer/8302904 to your computer and use it in GitHub Desktop.
Save cupakromer/8302904 to your computer and use it in GitHub Desktop.
Blog: Handling multiple examples with RSpec

Normally when testing objects with RSpec, I prefer to setup the object state in top-level as context. Inside those contexts, the behavior (messages) are then each tested inside of that state. See ("TBD FILL IN HERE")[] for more details on this.

However, there are times you find yourself needing to pass in a lot of test cases for some behavior.

module FrequencyCounter
  def self.count(s1, s2)
    [-1, 0, 1]
  end
end

Using Shared Examples

It leads to more lines, however, it is a bit more explicit in what the intent.

describe FrequencyCounter do

  subject(:counter) { FrequencyCounter }

  shared_examples "counting word frequencies" do |source:, target_words:, with_frequency:, description: nil|
    it (description || "parses #{source.inspect} and #{target_words.inspect} into #{with_frequency.inspect}") do
      expect(counter.count(source, target_words)).to eq with_frequency
    end
  end

  include_examples "counting word frequencies",
                   source: "foo bar",
                   target_words: "having fun",
                   with_frequency: [-1,0,1]
  include_examples "counting word frequencies",
                   source: "baz bar",
                   target_words: "not fun",
                   with_frequency: [-1,0,1],
                   description: "edge case for something"

end

It's also possible to use plain Ruby enumerables for this type of repeated example testing.

describe FrequencyCounter do

  subject(:counter) { FrequencyCounter }

  context "counting word frequencies" do

    examples = [
      [ "foo bar", "having fun", [-1, 0, 1] ],
      [ "baz bar", "not fun", [-1, 0, 1], "edge case for something" ],
    ]

    examples.each do |source, target_words, with_frequency, description|
      it (description || "parses #{source.inspect} and #{target_words.inspect} into #{with_frequency.inspect}") do
        expect(counter.count(source, target_words)).to eq with_frequency
      end
    end

  end

end



Of course there's nothing stopping you from combining these together.
describe FrequencyCounter do

  subject(:counter) { FrequencyCounter }

  shared_examples "counting word frequencies" do |examples:|

    examples.each do |opts|
      source = opts.fetch(:source)
      target_words = opts.fetch(:target_words)
      has_frequency = opts.fetch(:has_frequency)
      description_text = opts.fetch(:description){
        "parses #{source.inspect} and #{target_words.inspect} into " \
        "#{has_frequency.inspect}"
      }

      it description_text do
        expect(counter.count(source, target_words)).to eq has_frequency
      end
    end

  end

  it_behaves_like "counting word frequencies", examples: [
    {
      source: "foo bar",
      target_words: "having fun",
      has_frequency: [-1, 0, 1]
    },
    {
      source: "baz bar",
      target_words: "not fun",
      has_frequency: [-1, 0, 1],
      description: "edge case for something"
    },
  ]

end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment