2013-06-27 2 views
0

Есть простой тест:консоли говорит переменная не ноль, в тестах это ноль

context "in the same board" do 
    @link = FactoryGirl.create(:link_with_board, url: "www.onet.pl") 
    @board = @link.board 
    it "is invalid when the same url already exists" do 
     expect(@board.links.build(url: "www.onet.pl")).to_not be_valid 
     expect(@board.links.build(url: "http://www.onet.pl")).to_not be_valid 
     expect(@board.links.build(url: "www.onet.pl/")).to_not be_valid 
    end 
    end 

Он показывает мне ошибку:

Failures: 

    1) Link in the same board is invalid when the same url already exists 
    Failure/Error: expect(@board.links.build(url: "www.onet.pl")).to_not be_valid 
    NoMethodError: 
     undefined method `links' for nil:NilClass 
    # ./spec/models/link_spec.rb:50:in `block (3 levels) in <top (required)>' 

Когда я пытаюсь то же самое в консоли, все работает отлично. Любая идея почему?

Update:

Хорошо, я сделал его работу, но до сих пор вопрос остается тем же, почему первый не работает?

context "in the same board" do 
    #FIX START 
    before :each do 
     @link = FactoryGirl.create(:link_with_board, url: "www.onet.pl") 
     @board = @link.board 
    end 
    #FIX END 
    it "is invalid when the same url already exists" do 
     expect(@board.links.build(url: "www.onet.pl")).to_not be_valid 
     expect(@board.links.build(url: "http://www.onet.pl")).to_not be_valid 
     expect(@board.links.build(url: "www.onet.pl/")).to_not be_valid 
    end 
    end 
+0

Используйте 'let' вместо переменного экземпляра. – Hauleth

ответ

3

Вы устанавливаете @link и @board в блок context. Это разный масштаб для блока it, поэтому, когда блок it работает, эти переменные не определены.

За кулисами, context создает класс и it создает метод, так что вы делали, было что-то похожее на это:

class MyExampleGroup 
    @link = FactoryGirl.create(:link_with_board, url: "www.onet.pl") 
    @board = @link.board 

    def it_is_invalid_sometimes 
    @board.nil? # => true 
    end 
end 

Экземпляр переменная набор в области видимости класса виден в классе, но а не в классах.

Когда вы переместили их перед тем, сформированная структура была больше, как это:

class MyExampleGroup 
    def before 
    @link = FactoryGirl.create(:link_with_board, url: "www.onet.pl") 
    @board = @link.board 
    end 

    def it_is_invalid_sometimes 
    @board.nil? # => false 
    end 
end 

Теперь переменные экземпляра определяется в рамках экземпляра, поэтому они работают, как вы ожидаете.

(я немного упростив для ясности: методы, созданных it звонков фактически возвращают RSpec::Core::Example объектов, а before блоков работают на этих объектах, использующих instance_exec.)

+0

+1 для этого ответа. – Domon

1

Если запустить консоль с помощью простого rails console команды, он подключается к базе данных развития (в обычной конфигурации). Но тесты выполняются в тестовой базе данных.

В тесте, линия создания @link:

@link = FactoryGirl.create(:link_with_board, url: "www.onet.pl") 

Вы можете проверить, как определяется :link_with_board завод. (Возможно, в spec/factories/*.rb.)

+0

'RAILS_ENV = test rails console' может переключиться на тестовую базу данных, хотя обычно тестовая база данных пуста, потому что тесты выполняются внутри транзакции. – tadman

+0

-1: RAILS_ENV здесь не проблема, это проблема с проблемой ivar. – georgebrock

+0

@georgebrock: Я этого не заметил. Ты прав. :) – Domon