Подтвердить что ты не робот

Как RSpec ожидает работу в ROR

Просматривая учебник по Ruby On Rails Майкла Хартла, в разделе, где автор пишет интеграционный тест для проверки своей страницы регистрации, он использовал приведенный ниже код. Я получил то, что сделал код, но не мог окунуться в "часть", то есть не смог понять порядок выполнения.

expect { click_button "Create my account" }.not_to change(User, :count)

Может кто-нибудь объяснить семантику вышеприведенной цепи методов и блоков и как они подходят друг другу?

4b9b3361

Ответ 1

Вы использовали бы expect ... change для проверки того, что вызов определенного метода изменяется или не изменяется - какое-то другое значение. В этом случае:

expect { click_button "Create my account" }.not_to change(User, :count)

приведет к тому, что rspec сделает следующее:

  • Запустите User.count и обратите внимание на возвращаемое значение. (Это может быть указано как получатель и имя метода, например (User, :count) в вашем примере, или как произвольный блок кода, например { User.count }.
  • Запустите click_button "Create my account", который является методом Capybara, который имитирует щелчок мышью по ссылке.
  • Запустите User.count снова.
  • Сравните результаты # 1 и # 3. Если они отличаются, пример не выполняется. Если они совпадают, они проходят.

Другие способы использования expect ... change:

expect { thing.destroy }.to change(Thing, :count).from(1).to(0)
expect { thing.tax = 5 }.to change { thing.total_price }.by(5)
expect { thing.save! }.to raise_error
expect { thing.symbolize_name }.to change { thing.name }.from(String).to(Symbol)

Некоторые документы здесь.

Как это происходит, это немного загадочно, и совсем не нужно понимать, как это работает, чтобы использовать его. Вызов expect определяет структуру для rspec для выполнения, используя собственный DSL-интерфейс и систему "сопоставлений". Гэри Бернхардт имеет довольно аккуратный screencast, в котором он утверждает, что тайна rspec фактически выпадает естественным образом из динамического языка, такого как рубин. Это не хорошее введение в использование rspec, но если вам интересно, как все это работает, вам может показаться интересным.

UPDATE

После просмотра комментария к другому ответу я немного добавлю порядок операций. Неинтуитивный трюк заключается в том, что он является совпадающим (change в этом случае), который выполняет все блоки. expect имеет lambda, not_to является псевдонимом для should_not, задачей которого является передать лямбда на совпадение. Матчи в этом случае change, который знает, чтобы выполнить свой собственный аргумент один раз, затем выполнить lambda, который он передал (один из expect), а затем снова запустить свой собственный аргумент, чтобы узнать, изменились ли все. Это сложно, потому что строка выглядит так, как будто она должна выполняться слева направо, но так как большинство частей просто обходят блоки кода, они могут и перетасовывать их в любой порядок, который имеет наибольший смысл для совпадения.

Я не специалист по внутренним функциям rspec, но я понимаю основную идею.

Ответ 2

Здесь выдержка из Райан Бэйтс Railscast по спецификациям запросов и Capybara

require 'spec_helper'  

describe "Tasks" do  
  describe "GET /tasks" do  
    it "displays tasks" do  
      Task.create!(:name => "paint fence")  
      visit tasks_path  
      page.should have_content("paint fence")  
    end  
  end  

  describe "POST /tasks" do  
    it "creates a task" do  
      visit tasks_path  
      fill_in "Name", :with => "mow lawn"  
      click_button "Add"  
      page.should have_content("Successfully added task.")  
      page.should have_content("mow lawn")  
    end  
  end  
end  

И вот выдержка из документов на RSPec Expectations

describe Counter, "#increment" do
  it "should increment the count" do
    expect{Counter.increment}.to change{Counter.count}.from(0).to(1)
  end

  # deliberate failure
  it "should increment the count by 2" do
    expect{Counter.increment}.to change{Counter.count}.by(2)
  end
end

Итак, в основном,

expect { click_button "Create my account" }.not_to change(User, :count)

является частью RSpec:

expect {...}.not_to change(User, :count)

и часть Capybara

click_button "Create my account"

(Здесь ссылка на DSL Capyabara - вы можете искать click_button)

Похоже, вы ищете общий пример с ними обоими. Это не прекрасный пример, но он может выглядеть примерно так:

describe "Tasks" do  
  describe "GET /tasks" do  
    it "displays tasks" do  
      expect { click_button "Create my account" }.not_to change(User, :count)
    end  
  end 
end