如何重构这个rails规范?

时间:2016-10-20 08:00:20

标签: ruby rspec refactoring

请考虑以下代码段:

context 'votes' do
  it { should_not be_able_to :vote_yes, create(:question, user: user), user: user }
  it { should be_able_to :vote_yes, create(:question, user: other_user), user: user }
  it { should_not be_able_to :vote_no, create(:question, user: user), user: user }
  it { should be_able_to :vote_no, create(:question, user: other_user), user: user }
  it { should_not be_able_to :reject_vote, create(:question, user: user), user: user }
  it { should be_able_to :reject_vote, create(:question, user: other_user), user: user }

  it { should_not be_able_to :vote_yes, create(:answer, user: user), user: user }
  it { should be_able_to :vote_yes, create(:answer, user: other_user), user: user }
  it { should_not be_able_to :vote_no, create(:answer, user: user), user: user }
  it { should be_able_to :vote_no, create(:answer, user: other_user), user: user }
  it { should_not be_able_to :reject_vote, create(:answer, user: user), user: user }
  it { should be_able_to :reject_vote, create(:answer, user: other_user), user: user }
end

如何重构为少行和重复的东西?

1 个答案:

答案 0 :(得分:2)

我要做的第一件事就是将你的测试分成更多逻辑分组,因为它目前非常令人困惑(一目了然)预期的行为:

context 'voting yes' do
  it { should be_able_to :vote_yes, create(:answer, user: other_user), user: user }
  it { should_not be_able_to :vote_yes, create(:question, user: user), user: user }

  it { should be_able_to :vote_yes, create(:question, user: other_user), user: user }
  it { should_not be_able_to :vote_yes, create(:answer, user: user), user: user }
end

context 'voting no' do
  it { should be_able_to :vote_no, create(:question, user: other_user), user: user }
  it { should_not be_able_to :vote_no, create(:question, user: user), user: user }

  it { should be_able_to :vote_no, create(:answer, user: other_user), user: user }
  it { should_not be_able_to :vote_no, create(:answer, user: user), user: user }
end

context 'rejecting vote' do
  it { should be_able_to :reject_vote, create(:question, user: other_user), user: user }
  it { should_not be_able_to :reject_vote, create(:question, user: user), user: user }

  it { should be_able_to :reject_vote, create(:answer, user: other_user), user: user }
  it { should_not be_able_to :reject_vote, create(:answer, user: user), user: user }
end

查看这个重组的测试列表,可以更容易地看到明确的行为模式。您可以按如下方式删除重复:

%i(vote_yes vote_no reject_vote).each do |action_performed|
  context "can #{action_performed} against other users" do
    it { should be_able_to action_performed, create(:question, user: other_user), user: user }
    it { should be_able_to action_performed, create(:answer, user: other_user), user: user }
  end

  context "cannot #{action_performed} against self" do
    it { should_not be_able_to action_performed, create(:question, user: user), user: user }
    it { should_not be_able_to action_performed, create(:answer, user: user), user: user }
  end 
end

您甚至可能会更进一步,以消除questionanswer测试之间的重复:

%i(vote_yes vote_no reject_vote).each do |action_performed|
  %i(question answer).each do |record_type|
    it "can #{action_performed} against #{record_type} for other users" do
      should be_able_to action_performed, create(record_type, user: other_user), user: user 
    end

    it "cannot #{action_performed} against #{record_type} for self" do
      should_not be_able_to action_performed, create(record_type, user: user), user: user
    end
  end
end

然而,这可能会使测试更难理解和编辑,所以我建议反对它......也许如果记录类型列表(question,{ {1}},answer)增长的时间更长,然后您可以考虑这样的方法。