Подтвердить что ты не робот

Как работают переменные экземпляра в 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
4b9b3361

Ответ 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 под капотом.