Rspec:共享示例

时间:2013-04-06 22:43:01

标签: ruby-on-rails rspec dry

我有功能测试,它有两个重复的部分:

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。

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:2)

我认为您没有足够的类似代码来处理shared_examples_for块(尽管可以在 spec / support / utilities.rb 中为实用程序方法添加参数) ,所以我试图把它分开一点。

对于这个问题,很难定量给出正确的答案,因为很大程度上取决于你的编码风格,正如围绕@BillyChan的答案所讨论的那样。我的风格是尝试尽可能简洁可读;其他人可能会觉得它太干了,有些人认为不够干。不知道这是否真的有效,因为我没有你的代码,而是供你考虑......

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所要求的进一步说明:

specifyit的别名。我在这里使用specify因为我认为这句话读得更好(你可以很容易地将其替换为it)。此外,it块中的条件与subject的{​​{1}}相关,而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块。这都是品味和风格的问题。这个语法适用于此示例吗?你决定: - )