#rspec
#rspec
Вопрос:
Где я ошибаюсь?
describe '#update' do
let(:new_name) { Faker::Lorem.word }
let(:request) { patch :update, id: parent_folder.id, folder: { name: new_name, parent_id: nil, user_id: user.id } }
it 'should change the name' do
expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)
end
it 'does work gadnammit' do
ap parent_folder.reload.name #=> e.g. aqua
request
ap parent_folder.reload.name #=> e.g. hortis
end
end
Результатом ‘следует изменить имя’ является
Failure/Error: expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)# @new_name
expected #name to have changed from "maxime" to "jimmies", but did not change
И все же ‘does work gadnammit’ регистрирует два разных имени:
All examples were filtered out; ignoring {:focus=>true}
F."omnis"
"jimmies"
Failures:
1) FoldersController#update should change the name
Failure/Error: expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)# @new_name
expected #name to have changed from "maxime" to "jimmies", but did not change
# ./spec/controllers/folders_controller_spec.rb:62:in `block (3 levels) in <top (required)>'
Кроме того, когда вы используете помощник let с Faker, я знаю, что вы получаете новый результат каждый раз, когда вызывается создаваемая им переменная, что может создавать иллюзию, что имя меняется в спецификации ‘does work gadnammit’. Однако изменение его на жестко закодированную строку не дает никакой разницы:
let(:new_name) { "stagnant" }
Кроме того, эта спецификация:
it 'should make database queries' do
expect{ request }.to make_database_queries
end
проходит, поэтому я действительно думаю, что это работает…
SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
SELECT "folders".* FROM "folders" WHERE "folders"."user_id" = ? AND "folders"."id" = ? LIMIT 1
SAVEPOINT active_record_1
UPDATE "folders" SET "name" = ?, "updated_at" = ? WHERE "folders"."id" = 1
RELEASE SAVEPOINT active_record_1
(сопоставитель make_database_queries любезно предоставлен db-query-matchers gem)
TL;DR Почему нет
expect{ request }.to change(parent_folder.reload,:name).from(parent_folder.name).to(new_name)
работает?
Ответ №1:
Параметр parent.folder.rename
вычисляется во время change
вызова. Он не подвергается (и не может) повторной оценке после выполнения тестируемого блока. Это, скорее всего, объясняет, почему name
вызванный результирующий объект не изменяется.
Если вы хотите, чтобы выражение было повторно вычислено до и после выполнения тестируемого блока, вам необходимо передать change
блок, как в:
change { parent.folder.reload }.from(...).to(...)
«Параметрическая» версия change
работает, когда первый параметр остается неизменным (например, константой), а значение, возвращаемое методом, связанным со вторым параметром, изменяется.
Комментарии:
1. Спасибо, Питер! Жаль, что он не читается почти так же хорошо, как
expect{ request }.to change...
почему этоexpect{ delete :destroy, id: child_folder.id }.to change(Folder, :count).by(-1)
работает? Конечно, это должно оцениватьсяFolder.count
до и после выполнения запроса, так почему же это не работает при запросе фактической записи?2. Хорошо, я буду честен, я немного сбит с толку.
expect { employee.develop_great_new_social_networking_app }.to change(employee, :title).from("Mail Clerk").to("CEO")
из rubydoc.info/github/rspec/rspec-expectations/RSpec / … очень точно соответствует тому, что я хочу, и все же это не работает? Пожалуйста, пример 🙂3. Мне пришлось задать этот вопрос во второй раз. Не заметил фигурные скобки, игнорируйте меня: P