TDD RSpec 水豚 Ruby Rails

TDD RSpec Capybara Ruby on Rails

我正在尝试熟悉 Capybara 和其他 TDD,但我失败了。我在这里的第一个例子(场景 "unsuccessfully post a message no user" do)应该是失败的,因为我没有输入用户,但无论如何它都会以某种方式输入,而不是收到预期的 "User must exist" 它说 "Welcome John" .我的 'before(:each)' 是否在它出现后仍会击中它,还是我有其他问题?

/spec/features/mess_spec.rb

require 'rails_helper'
feature "post message" do
    scenario "unsuccessfully post a message no user" do
        visit messages_path
        fill_in "message[content]", with: "This is the content of my message."
        click_button "Post a Message"
        expect(page).to have_content "User must exist"      
    end
    before(:each) do 
        visit new_user_path
        fill_in "user[name]", with: "John"
        click_button "Sign In"
        visit messages_path
    end
    scenario "successfully post a message" do
        fill_in "message[content]", with: "This is the content of my message."
        click_button "Post a Message"
        expect(page).to have_content "This is the content of my message"
        expect(current_path).to eq(messages_path)
    end
    scenario "unsuccessfully post a message no content" do
        fill_in "message[content]", with: ""
        click_button "Post a Message"
        expect(page).to have_content "Content is too short"     
    end
    scenario "messages page should have a log out button" do
        click_button "logout"
        expect(current_path).to eq(new_user_path)
    end
end

我的 spec/models/message_spec.rb 在第二次测试时遇到了类似的问题


it "should not save if no user" do 
     expect(build(:message)).to be_invalid
   end     

也没有失败,尽管我只是通过跳过工厂机器人来作弊所以这是我当前的工作文件

require 'rails_helper'

RSpec.describe Message, type: :model do
    it "should save" do      
      expect(build(:message, user: build(:user))).to be_valid
    end
    it "should not save if no user" do 
      message = Message.new(
        content: 'This is a message'               
      )
      expect(message).to be_invalid
    end     
    it "should not save content is too short" do 
      message = Message.new(
        content: 'This',
        user_id: '1'       
      )
      expect(message).to be_invalid
    end         
end

您猜对了您的问题 - scenario 只是定义了测试 - 它没有定义测试的顺序,最佳做法实际上是 运行 您的测试以随机顺序确保您在各个测试之间没有任何耦合。这意味着在同一范围或更高范围内定义的任何 before(:each) 将在该范围内指定的每个 scenario 之前 运行。

要解决这个问题,您可以使用任何 RSpecs 其他关键字来形成新的范围,例如

feature "post message" do
    context "with no user" do
      scenario "unsuccessfully post a message no user" do
          visit messages_path
          fill_in "message[content]", with: "This is the content of my message."
          click_button "Post a Message"
          expect(page).to have_content "User must exist"      
      end
    end

    context "with a user" do
      before(:each) do 
        visit new_user_path
        fill_in "user[name]", with: "John"
        click_button "Sign In"
        visit messages_path
      end

      scenario "successfully post a message" do
        fill_in "message[content]", with: "This is the content of my message."
        click_button "Post a Message"
        expect(page).to have_content "This is the content of my message"
        expect(page).to have_current_path(messages_path)
      end
      scenario "unsuccessfully post a message no content" do
        fill_in "message[content]", with: ""
        click_button "Post a Message"
        expect(page).to have_content "Content is too short"     
      end
      scenario "messages page should have a log out button" do
        click_button "logout"
        expect(page).to have_current_path(new_user_path)
      end
    end
end

此外,您不应将 RSpecs 内置匹配器(eq 等)与 Capybara 一起使用 - 而是使用 Capybara 提供的匹配器,在本例中 have_current_path 如我所示多于。这些具有重试行为,并且在您处理包含异步行为的页面时会导致更稳定的测试。