3

我有功能测试,其中有 2 个重复的部分:

require 'spec_helper'

describe "Messages manage" do
  let (:user) { create :user }
  let (:other_user) { create :use }
  before(:each) do
    login_as user
  end

  describe "[message create]" do

    it "messages created by self, should appear on the page", js: true do
      message_text = "Hello my friend"

      visit user_messages_path(user, {with:other_user.id} )
      fill_in :message_body, with: message_text
      click_button t("users.messages.index.send")
      sleep 1 # waiting for js

      page.should have_content(message_text)
      find_field(:message_body).value.should == ""
      page.should have_selector('#message_body', visible: false)
    end

    it "message errors should be displayed", js: true do
      message_text = "123"

      visit user_messages_path(user, {with:other_user.id} )
      fill_in :message_body, with: message_text
      click_button t("users.messages.index.send")
      sleep 1 # waiting for js

      page.should_not have_content("Message: #{message_text}")
      find_field(:message_body).value.should == message_text
      page.should have_selector('.message.error', visible: true)
    end

  end
end

在这种情况下,使用 shared_examples 或类似方法的最佳方法是什么?跟随 DRY。

4

2 回答 2

3

您可以在代码下方附加特定方法

require 'spec_helper'

describe "Messages manage" do
  # let (:user) { create :user } 
  # Instead expose it as instance variable
  @user = create(:user)
  # let (:other_user) { create :user }
  @other_user = create(:user)
  before(:each) do
    login_as user
  end

  describe "[message create]" do

    it "messages created by self, should appear on the page", js: true do

      # Use the custom method
      send_message "Hello my friend"

      page.should have_content(message_text)
      find_field(:message_body).value.should == ""
      page.should have_selector('#message_body', visible: false)
    end

    it "message errors should be displayed", js: true do

      # Use the custom method
      send_message "123"

      page.should_not have_content("Message: #{message_text}")
      find_field(:message_body).value.should == message_text
      page.should have_selector('.message.error', visible: true)
    end

  end


  def send_message(message_text)
        visit user_messages_path(@user, {with:@other_user.id} )
        fill_in :message_body, with: message_text
        click_button t("@users.messages.index.send")
        sleep 1 # waiting for js
  end

end

对于更通用的代码,您可以将它们提取到模块中的规范/支持中。但是对于这种情况,上述方法应该足够好了。

于 2013-04-07T04:46:16.033 回答
2

我认为您没有足够相似的代码来使shared_examples_for块成为必要(尽管可以为spec/support/utilities.rb中的实用程序方法进行参数),因此我尝试将其拆分一下。

根据围绕@BillyChan 答案的讨论,很难定量地为您提供这个问题的正确答案,因为很大程度上取决于您的编码风格。我的风格是尽量简洁易读。其他人可能认为它太 DRY,有些不够 DRY。不知道这是否真的有效,因为我没有你的代码,但为了你的考虑......

require 'spec_helper'

describe "Message management" do

  let(:user)       { create :user }
  let(:other_user) { create :user }

  before { login_as user }

  subject { page }

  describe "message creation" do
    let(:send_button) { t("users.messages.index.send") }

    before { visit user_messages_path(user, { with: other_user.id }) }

    context "by self", js: true do
      let(:message_text) { "Hello my friend" }

      before do
        fill_in :message_body, with: message_text
        click_button send_button
        sleep 1 # waiting for js
      end

      it { should have_content(message_text) }
      it { should have_selector('#message_body', visible: false) }
      specify { find_field(:message_body).value.should == "" }
    end

    describe "message errors", js: true do
      let(:message_text) { "123" }

      before do
        fill_in :message_body, with: message_text
        click_button send_button
        sleep 1 # waiting for js
      end

      it { should_not have_content("Message: #{message_text}") }
      it { should have_selector('.message.error', visible: true) }
      specify { find_field(:message_body).value.should == message_text }
    end
  end        
end

根据@ole 的要求编辑进一步的解释:

specify是 的别名it。我specify在这里使用是因为我认为这个短语读起来更好(你可以很容易地将它替换为it)。此外,it块中的条件与subject的相关page,而specify块中的内容本质上不是直接引用page,而是“改变了subject”测试。如果我想将代码specify块中的代码放入我认为可读的块中,尽管更冗长,it块,我可能会将其更改为:

describe "message errors", js: true do
  let(:message_text) { "123" }

  before do
    fill_in :message_body, with: message_text
    click_button send_button
    sleep 1 # waiting for js
  end

  it { should_not have_content("Message: #{message_text}") }
  it { should have_selector('.message.error', visible: true) }

  describe "message body value" do
    let(:message_body) { find_field(:message_body).value }
    subject { message_body }
    it { should == message_text }
  end
end

如果需要,您也可以删除该let语句并find_field(:message_body).value直接放入subject块中。这完全取决于品味和风格。此语法是否适合此示例?你决定 :-)

于 2013-04-07T05:59:30.577 回答