Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rspec: DRY Shared Examples for Positive and Negative Cases

Using RSpec, how do I write a group of shared_examples that is DRY and can be used for positive and negative cases?

Example of shared_examples that works for positive cases:

shared_examples "group1" do
  it "can view a person's private info" do
    @ability.should be_able_to(:view_private_info, person)
  end
  # also imagine I have many other examples of positive cases here
end

If there's something opposite of it_should_behave_like, like it_should_not_behave_like, that'd be great. I understand the text of the example will have to be flexible.

like image 689
konyak Avatar asked Apr 03 '14 14:04

konyak


1 Answers

You could do it like this:

Classes under test:

class Hat
  def goes_on_your_head?
    true
  end

  def is_good_to_eat?
    false
  end

end

class CreamPie
  def goes_on_your_head?
    false
  end

  def is_good_to_eat?
    true
  end

end

Examples:

shared_examples "a hat or cream pie" do
  it "#{is_more_like_a_hat? ? "goes" : "doesn't go" } on your head" do
    expect(described_class.new.goes_on_your_head?).to eq(is_more_like_a_hat?)
  end

  it "#{is_more_like_a_hat? ? "isn't" : "is" } good to eat" do
    expect(described_class.new.is_good_to_eat?).to eq(!is_more_like_a_hat?)
  end

end

describe Hat do
  it_behaves_like "a hat or cream pie" do
    let(:is_more_like_a_hat?) { true }
  end
end

describe CreamPie do
  it_behaves_like "a hat or cream pie" do
    let(:is_more_like_a_hat?) { false }
  end
end

I would be less likely to do this in real code, since it would be hard to write comprehensible example descriptions. Instead, I'd make two shared examples and extract the duplication into methods:

def should_go_on_your_head(should_or_shouldnt)
  expect(described_class.new.goes_on_your_head?).to eq(should_or_shouldnt)
end

def should_be_good_to_eat(should_or_shouldnt)
  expect(described_class.new.is_good_to_eat?).to eq(should_or_shouldnt)
end

shared_examples "a hat" do
  it "goes on your head" do
    should_go_on_your_head true
  end

  it "isn't good to eat" do
    should_be_good_to_eat false
  end

end

shared_examples "a cream pie" do
  it "doesn't go on your head" do
    should_go_on_your_head false
  end

  it "is good to eat" do
    should_be_good_to_eat true
  end

end

describe Hat do
  it_behaves_like "a hat"
end

describe CreamPie do
  it_behaves_like "a cream pie"
end

Of course I wouldn't extract those methods or even use shared examples at all unless the actual examples were complicated enough to justify it.

like image 78
Dave Schweisguth Avatar answered Nov 15 '22 06:11

Dave Schweisguth