2017-01-19 5 views
2

Я знаю, что expect(assign(:var)) в тестах контроллеров указывает, что @var получает определенное значение. В моем случае я хочу проверить, получает ли это @var определенное сообщение. Если я сделаю это до get :action, то присваивание возвращает nil. Если я это сделаю, слишком поздно ожидать сообщения.RSpec, проверяющий переменную экземпляра контроллера, получает сообщение

# controller 
def action 
    @var = something 
    @var.message 
    render :nothing 
end 

# spec1 
expect(assigns(:var)).to receive(:message) # not working, var is nil 
get :action 

# spec2 
get :action 
expect(assigns(:var)).to receive(:message) # not working, expectation too late 

ответ

2

То, что вы ищете, это испытания двойников или издевательства. Вы можете использовать их, добавив жемчуг rspec-mocks или другой тестовый двойной драгоценный камень, например RR.

После того как вы один из них (я лично использую RR), вы можете сделать это (синтаксис для RR):

mock(assigns(:var)).foo 
get :action 

не на 100% уверен в синтаксисе rspec-mocks но это должно выглядеть примерно так :

var = double(assigns(:var)) 
expect(var).to receive(:foo) 
get :action 

вы должны смотреть на README для Message Expectations и Expecting Arguments, если вам нужно добавить больше проверок.

+0

Пробовал использовать rspec-mocks, но это не сработало, или я не мог понять, как это должно быть написано: 'var = spy (assigns (: var), action: 1); get: action, id: 10; ожидать (var) .to have_received (: action) ' – hammady

+0

К сожалению,' assigns (: var) 'будет возвращать' nil', если вызывается перед 'get: action', и это весь вопрос в моем вопросе. Для этого я попробовал 'spy' вместо' double', который тоже не работал. – hammady

+0

Возможно, попробуйте '@ var' вместо' assigns (: var) '? –

0

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

Вместо этого я обычно ожидать от «any_instance_of», как это:

expect_any_instance_of(ClassOfVar).to receive(:message) 
+0

Хотя ожидается, что какой-либо экземпляр будет работать, но небезопасно предположить, что любой экземпляр может получить сообщение, и тест пройдет. – hammady

+1

Я согласен, что это не будет работать во всех случаях, и что это не идеально, но он работает для меня в большинстве случаев, и это единственное решение проблемы, которую вы описываете, что я знаю :-) Я взволнован, чтобы увидеть, есть ли у кого-то другое идеальное решение вашей проблемы без каких-либо недостатков, но пока это лучшее, что я смог придумать :-) – kaspernj

0

В настоящее время я принуждая переменную экземпляра контроллера ожидать сообщений о. Несмотря на то, что это работает, но он пропускает загрузочную логику (канкан), так что я создал еще один тест для этого:

it "loads and authorizes object" do 
    get :action, id: 10 
    assert_response :success 
    end 

    it "calls action on object" do 
    controller.instance_variable_set('@var', @my_real_object_or_mock_here) 
    expect(@my_real_object_or_mock_here).to receive(:message) 
    get :action, id: 10 
    assert_response :success 
    end 

Я вроде найти это решение Hacky, но если этот ответ получает наибольшее количество голосов, я буду принимать его:)