Как работают переменные экземпляра в rspec?
Вот немного кода из M Hartl Ruby on Rails Tutorial. Может ли кто-нибудь объяснить, почему нужна переменная экземпляра (@user) и почему бы не использовать локальную переменную. Кроме того, поскольку переменные экземпляра должны быть переменными в экземпляре класса, из которого класс является @user, созданным из?
require 'spec_helper'
describe User do
before { @user = User.new(name: "Example User", email: "[email protected]") }
subject { @user }
it { should respond_to(:name) }
it { should respond_to(:email) }
end
Ответы
Ответ 1
Использование локальной переменной в этом экземпляре означает, что ее область будет ограничена before
и, следовательно, приведет к ошибке. @user
имеет тип User, но является переменной экземпляра блока describe
. Rspec обладает некоторой магией, которая во время выполнения делает класс из каждого блока describe
. Каждый пример (блок it
) становится подклассом указанного класса. Наследование классов позволяет видеть примеры @user
.
Отредактировано 2017-05-14
Ссылка на сообщение в блоге больше не доступна. Обновление с помощью Wayback Machine link + вставка соответствующей секции здесь.
Обратите внимание, что это считается анти-шаблоном, подробно описанным в этом сообщении в блоге. Вместо этого используйте let
.
let
имеет следующие преимущества:
- Это memoize, когда используется несколько раз в одном примере, но не
через примеры.
- Он ленивый, поэтому вы не тратите время на инициализацию переменной для примеров, которые не ссылаются на нее.
- Поднимет исключение, если у вас есть опечатка в имени переменной.
Ответ 2
Вы не можете использовать локальную переменную, поскольку локальная переменная существует только в области локального метода. before
, subject
и it
генерируют разные области видимости в пределах одного класса.
Следующий код
before { user = User.new(name: "Example User", email: "[email protected]") }
подведет переменную undefined, когда вы вызовете ее в
subject { user }
Экземпляр @user
является экземпляром класса User
(в конце концов, вы создаете его с помощью User.new
).
Однако вместо переменных экземпляра вы можете использовать команду let
. Кроме того, если вы определяете
subject { User.new(name: "Example User", email: "[email protected]") }
использование before
не требуется. Вы также получите дополнительное преимущество, чтобы получить доступный метод subject
для доступа к экземпляру, равный определению let(:subject)
.
Ответ 3
subject
ad it
блоки находятся в разных областях, поэтому локальные переменные не будут работать. @user
принадлежит классу, сгенерированному RSpec под капотом.