В чем разница между предметом RSpec и let? Когда они должны использоваться или нет?

ruby unit-testing rspec

19264 просмотра

3 ответа

803 Репутация автора

http://betterspecs.org/#subject имеет некоторую информацию о subjectи let. Однако мне все еще неясно, в чем разница между ними. Более того, пост SO Каков аргумент против использования before, let и subject в тестах RSpec? сказал , что лучше не использовать или subjectили let. Куда мне идти? Я так растерялся.

Автор: new2cpp Источник Размещён: 18.07.2016 12:49

Ответы (3)


1 плюс

1472 Репутация автора

subjectэто то, что тестируется, обычно это экземпляр или класс. letпредназначен для назначения переменных в ваших тестах, которые оцениваются лениво по сравнению с использованием переменных экземпляра. В этой теме есть несколько хороших примеров.

https://github.com/reachlocal/rspec-style-guide/issues/6

Автор: nikkypx Размещён: 18.07.2016 05:01

3 плюса

1164 Репутация автора

Subjectи letпросто инструменты, которые помогут вам привести в порядок и ускорить ваши тесты. Люди в сообществе rspec используют их, поэтому я не буду беспокоиться о том, можно ли их использовать или нет. Они могут использоваться аналогично, но служат немного другим целям

Subjectпозволяет вам объявить объект тестирования, а затем повторно использовать его для любого количества последующих тестов. Это уменьшает повторение кода (высушивание кода)

Letявляется альтернативой before: eachблокам, которые присваивают тестовые данные переменным экземпляра. Letдает вам пару преимуществ. Во-первых, он кэширует значение, не назначая его переменной экземпляра. Во-вторых, он лениво оценивается, что означает, что он не будет оценен, пока спецификация не вызовет его. Это letпоможет вам ускорить ваши тесты. Я тоже думаю letпроще читать

Автор: Ren Размещён: 18.07.2016 05:02

130 плюса

27677 Репутация автора

Решение

Резюме: Предмет RSpec - это специальная переменная, которая относится к тестируемому объекту. Ожидания могут быть установлены на нем неявно, что поддерживает однострочные примеры. Это понятно читателю в некоторых идиоматических случаях, но в противном случае его трудно понять, и его следует избегать. letПеременные RSpec - это просто ленивые (записанные) переменные. За ними не так сложно следить, как за предметом, но они все же могут привести к запутанным тестам, поэтому их следует использовать с осторожностью.

Предмет

Как это устроено

Предмет - это объект, который тестируется. RSpec имеет четкое представление о предмете. Это может или не может быть определено. Если это так, RSpec может вызывать методы, не обращаясь к нему явно.

По умолчанию, если первым аргументом для самой внешней группы примеров ( describeили contextблока) является класс, RSpec создает экземпляр этого класса и назначает его субъекту. Например, следующие проходы:

class A
end

describe A do
  it "is instantiated by RSpec" do
    expect(subject).to be_an(A)
  end
end

Вы можете определить предмет самостоятельно с помощью subject:

describe "anonymous subject" do
  subject { A.new }
  it "has been instantiated" do
    expect(subject).to be_an(A)
  end
end

Вы можете дать субъекту имя при его определении:

describe "named subject" do
  subject(:a) { A.new }
  it "has been instantiated" do
    expect(a).to be_an(A)
  end
end

Даже если вы называете тему, вы все равно можете обратиться к ней анонимно:

describe "named subject" do
  subject(:a) { A.new }
  it "has been instantiated" do
    expect(subject).to be_an(A)
  end
end

Вы можете определить более одного именованного субъекта. Последний определенный названный предмет - аноним subject.

Однако предмет определен,

  1. Это ленивый экземпляр. То есть неявное создание экземпляра описанного класса или выполнение переданного блока subjectне происходит до тех пор, пока subjectв примере не будет указана именованная тема. Если вы хотите, чтобы ваш предмет экспликации создавался с нетерпением (до запуска примера в его группе), скажите subject!вместо subject.

  2. Ожидания могут быть установлены на нем неявно (без написания subjectили имени названного субъекта):

    describe A do
      it { is_expected.to be_an(A) }
    end
    

    Субъект существует для поддержки этого однострочного синтаксиса.

Когда его использовать

Неявное subject(выведенное из примера группы) трудно понять, потому что

  • Он создан за кулисами.
  • Используется ли он неявно (путем вызова is_expectedбез явного получателя) или явно (как subject), он не дает читателю никакой информации о роли или природе объекта, для которого вызывается ожидание.
  • Примерный однострочный синтаксис не имеет описания примера (строковый аргумент itв обычном синтаксисе примера), поэтому единственная информация, которую читатель имеет о цели примера, - это само ожидание.

Следовательно, полезно использовать неявный субъект только тогда, когда контекст, вероятно, будет хорошо понят всеми читателями, и в действительности нет необходимости в описании примера . Канонический случай - это проверка валидаций ActiveRecord с помощью совпадений musta:

describe Article do
  it { is_expected.to validate_presence_of(:title) }
end

Анонимный экспликт subject(определенный subjectбез имени) немного лучше, потому что читатель может увидеть, как он создан, но

  • он по-прежнему может поставить инстанцирование субъекта далеко от того места, где он используется (например, в верхней части группы примеров со многими примерами, которые его используют), что все еще трудно соблюдать, и
  • у него есть другие проблемы, которые делает неявный субъект.

Именованный субъект предоставляет имя, раскрывающее намерение, но единственная причина использования именованного субъекта вместо letпеременной состоит в том, что если вы хотите использовать анонимный субъект иногда, и мы только что объяснили, почему анонимный субъект трудно понять.

Таким образом, законное использование явного анонимного subjectили именованного субъекта очень редко .

let переменные

Как они работают

let переменные похожи на именованные предметы, за исключением двух различий:

  • они определены с let/ let!вместо subject/subject!
  • они не устанавливают анонимность subjectи не позволяют косвенно вызывать ожидания.

Когда их использовать

Это вполне законно, letчтобы уменьшить дублирование примеров. Тем не менее, делайте это только тогда, когда это не жертвует ясностью теста. Самое безопасное время для использования let- это когда letцель переменной полностью понятна из ее имени (так что читателю не нужно находить определение, которое может быть за много строк, чтобы понять каждый пример), и она используется таким же образом в каждом примере. Если что-то из этого не соответствует действительности, рассмотрите определение объекта в простой старой локальной переменной или вызов метода фабрики прямо в примере.

let!это рискованно, потому что это не лень. Если кто-то добавляет пример в группу примеров, которая содержит let!, но в примере let!переменная не нужна ,

  • этот пример будет трудно понять, потому что читатель увидит let!переменную и спросит себя, влияет ли это на пример и как
  • пример будет медленнее, чем нужно, из-за времени, затрачиваемого на создание let!переменной

Так что используйте let!, если вообще, только в небольших, простых группах примеров, где менее вероятно, что будущие авторы примеров попадут в эту ловушку.

Фетиш с одним ожиданием на пример

Существует общее злоупотребление предметами или letпеременными, которые стоит обсудить отдельно. Некоторые люди любят использовать их так:

describe 'Calculator' do
  describe '#calculate' do
    subject { Calculator.calculate }
    it { is_expected.to be >= 0 }
    it { is_expected.to be <= 9 }
  end
end

(Это простой пример метода, который возвращает число, для которого нам нужно два ожидания, но этот стиль может иметь гораздо больше примеров / ожиданий, если метод возвращает более сложное значение, которое требует много ожиданий и / или имеет много побочных эффектов, которые всем нужны ожидания.)

Люди делают это потому, что слышали, что в каждом примере должно быть только одно ожидание (которое смешивается с действующим правилом, согласно которому следует проверять только один вызов метода в каждом примере), или потому что они любят хитрость RSpec. Не делайте этого с анонимным или именованным субъектом или с letпеременной! У этого стиля есть несколько проблем:

  • Анонимный предмет не является предметом примеров - метод является предметом. Написание теста таким образом портит язык, делая его труднее думать.
  • Как всегда в однострочных примерах, нет смысла объяснять смысл ожиданий.
  • Предмет должен быть построен для каждого примера, который является медленным.

Вместо этого напишите один пример:

describe 'Calculator' do
  describe '#calculate' do
    it "returns a single-digit number" do
      result = Calculator.calculate
      expect(result).to be >= 0
      expect(result).to be <= 9
    end
  end
end
Автор: Dave Schweisguth Размещён: 19.07.2016 12:46
Вопросы из категории :
32x32