RSpec Scaffold Controller, понимание значений по умолчанию - PullRequest
1 голос
/ 04 февраля 2011

Я работаю через учебник rspec (учебник peepcode).Я сгенерировал некоторые строительные леса и надеялся, что кто-нибудь может помочь объяснить, как можно переписать описание, чтобы оно было более понятным для новичка.

describe "POST create" do

    describe "with valid params" do
      it "assigns a newly created weather as @weather" do
        Weather.stub(:new).with({'these' => 'params'}) { mock_weather(:save => true) }
        post :create, :weather => {'these' => 'params'}
        assigns(:weather).should be(mock_weather)
      end

end

Эта строка кода - это то, что я пытаюсь понять:

Weather.stub(:new).with({'these' => 'params'}) { mock_weather(:save => true) }

Я никогда не видел, чтобы метод был заключен в фигурные скобки.Что это на самом деле означает?

{ mock_weather(:save => true) }

Ответы [ 2 ]

6 голосов
/ 04 февраля 2011

Это утверждение означает:

Заглушите метод new в классе Weather с параметрами 'these'=>'params' и верните значение выражения mock_weather(:save => true)

Аналогичный и, возможно, более понятный способ написать это будет:

Weather.stub(:new).with({'these'=>'params'}).and_return(mock_weather(:save => true))

Синтаксис { <<code>some code> } создает кодовый блок , который выполняется при вызове заглушки.

Возвращаемые значения двух форм .and_return() и {} немного отличаются; в первом случае это определяется при определении заглушки, во втором случае определяется при получении сообщения. Они обычно взаимозаменяемы - , но иногда не .

EDIT

Я чувствую этот ответ вводит в заблуждение насчет насмешек и заслуживает ответа:

Что касается вашего первого вопроса о том, "как чтобы сделать это немного яснее ", мы могли бы начать с использования не издевается. Издеваться объект полезен когда не можешь зависит от предсказуемого поведения вторичный объект, объект, который является не важно, но должно присутствовать в ваш тестовый случай. Типичные примеры использование макетов объектов базы данных запросы, использование сети, файловый ввод / вывод. Вы не хочу, чтобы ваши тесты провалились, потому что ваш компьютер потерял соединение с сетью, или база данных недоступна.

Правда, макеты могут устранить зависимости от внешних ресурсов, но это не единственная их цель. Настоящая ценность mocks заключается в том, что они позволяют вам писать тесты для кода, который еще не существует. Например, в Rails вы можете начать с написания спецификаций вида.

describe "posts/show.html.erb" do
  it "displays the author name" do
    assign(:post,mock('post',:author=>"Mark Twain"))
    render
    rendered.should contain("written by Mark Twain")
  end
end

Эта спецификация не требует существования базы данных, контроллера или модели. Все, что он делает, это утверждает, что представление должно визуализировать строку и проверять, что она визуализируется - это все, что должно быть связано с представлением Rails. Единственными зависимостями являются наличие файла шаблона и переменной экземпляра @post, которая обрабатывается оператором assign. Его даже не волнует, что такое @post, только то, что он отвечает на :author.

Сгенерированный код, который вы получили от рельсы г эшафот не оптимальны. Сгенерированный код был сгенерирован в способ пройти все тесты, и для этого он использует фиктивные объекты. Я не знаю, почему они это делают, я думаю, лучше по умолчанию будет провал тестов так что вам на самом деле нужно сделать что-то, чтобы заставить их пройти.

Вся идея скаффолда состоит в том, чтобы сэкономить время, генерируя код, который работает для обычных случаев использования. Разве вы не хотите, чтобы сгенерированные тесты действительно работали?

Конечно, используя scaffolding, вы выполняете конечный прогон парадигмы BDD / TDD «test first», но, по-видимому, вы приняли соответствующие компромиссы, иначе вы не будете использовать скаффолды в первую очередь.

Что касается «зачем использовать фиктивные объекты», они позволяют отделить спецификацию контроллера от модели и базы данных. Так что да, это «оптимально», если вы знаете причину.

С автоматически генерируемыми фиктивными файлами вы не нужно ничего делать вообще и тесты продолжат проходить навсегда. Это плохая идея и плохая практика.

Они будут проходить только до тех пор, пока вы не нарушите предметный код. Таким образом, они имеют значение в регрессионном тестировании, чтобы гарантировать, что вы не вводите новый код или рефакторинг таким образом, что код больше не соответствует спецификациям.

Так как придётся писать правила проверки в вашем файле модели, и вы не используете фиктивный объект, Вы можете быть уверены, что фактический проверка продолжается.

Этот видсвязи на самом деле нежелательно в спецификации контроллера Rails. Контроллер должен знать как можно меньше о модели, поэтому спецификации контроллера должны определять только то, что происходит, когда валидация проходит (или не проходит) - и именно это делает макет, предоставляемый скаффолдом. Если вам необходимо проверить, является ли экземпляр модели действительным для данного набора параметров, сделайте это в спецификации модели.

1 голос
/ 04 февраля 2011

Что касается вашего первого вопроса о "как сделать это немного яснее" , мы могли бы начать с использования макетов.

Макет объекта полезен, когда вы не можете зависеть от предсказуемого поведения вторичного объекта, объекта, который не важен, но должен присутствовать в вашем тестовом примере. Типичными примерами использования фиктивных объектов являются запросы к базе данных, использование сети, файловый ввод-вывод. Вы не хотите, чтобы ваши тесты не прошли, потому что ваш компьютер потерял сетевое соединение или база данных недоступна.

Сгенерированный код, полученный из rails g scaffold, не является оптимальным. Сгенерированный код был сгенерирован таким образом, что все тесты пройдут успешно, и для этого используются фиктивные объекты. Я не знаю, почему они это делают, я думаю, что лучшим вариантом по умолчанию были бы неудачные тесты, так что вам действительно нужно что-то сделать , чтобы они прошли.

Я бы удалил сгенерированные макеты и сделал бы что-то вроде следующего:

#spec/controllers/weather_controller_spec.rb
describe "POST create" do
  describe "with valid params" do
    it "assigns a newly created weather as @weather" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      assigns(:weather).should be_valid
    end

    it "should redirect you to the weather show page" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      response.should redirect_to(weather_path(assigns[:weather]))
    end
  end

  describe "without valid params" do
    it "should notify that a location is required" do
      post :create, :weather => {'temp'=>'35', 'sample_time'=>'2011-02-04T20:00-0500'}
      flash[:notice].should == 'Location is required.'
      assigns(:weather).should_not be_valid
    end

    it "should notify that a temperature is required" do
      post :create, :weather => {'location' => 'ORD', 'sample_time'=>'2011-02-04T20:00-0500'}
      flash[:notice].should == 'A temperature is required.'
      assigns(:weather).should_not be_valid
    end

    it "should notify that a sample time is required" do
      post :create, :weather => {'location' => 'ORD', 'temp'=>'35'}
      flash[:notice].should == 'A sample time is required.'
      assigns(:weather).should_not be_valid
    end
  end
end

Обратите внимание, что мы не используем фиктивные объекты, и поэтому код сводится к выполнению вызова POST с некоторыми параметрами и проверке того, что объект действителен. Так как вам придется записывать правила проверки в файл модели, а вы не используете фиктивный объект, вы можете быть уверены, что происходит фактическая проверка.

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

Также обратите внимание, что вам следует написать больше тестов, в которых используются случаи, когда есть недопустимые или отсутствующие параметры. И снова, выполнив assigns(:weather).should_not be_valid, вы проверяете, что ваши проверки выполняют свою работу.

Запись словаря параметров каждый раз, когда вы вызываете post :create, повторяется, хрупка и безобразна. Вы должны изучить, как использовать светильники. Например, с Factory Girl

#spec/factories.rb
Factory.define :weather_valid do |f|
  f.location "ORD"
  f.temp "35"
  f.sample_time "2011-02-04T20:00-0500"
end


#spec/controllers/weather_controller_spec.rb
describe "POST create" do
  describe "with valid params" do
    it "assigns a newly created weather as @weather" do
      post :create, :weather => Factory.build(:weather_valid).attributes
      assigns(:weather).should be_valid
    end

    it "should redirect you to the weather show page" do
      post :create, :weather => Factory.build(:weather_valid).attributes
      response.should redirect_to(weather_path(assigns[:weather]))
    end
  end
...

Это дает вам повторно используемый и более читаемый код.

...