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

<http://betterspecs.org/#subject> имеет некоторую информацию о`subject` а также`let`, Однако мне все еще неясно, в чем разница между ними. Кроме того, SO сообщение[Какой аргумент против использования before, let и subject в тестах RSpec?](https://stackoverflow.com/questions/12869026/what-is-the-argument-against-using-before-let-and-subject-in-rspec-tests) сказал, что лучше не использовать либо`subject` или же`let`, Куда мне идти? Я так растерялся.

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

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

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

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

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

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

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

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

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

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

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

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

Он создан за кулисами.Используется ли это неявно (вызывая`is_expected` без явного получателя) или явно (как`subject`), он не дает читателю никакой информации о роли или природе объекта, по которому вызывается ожидание.Синтаксис примера с одной строкой не имеет описания примера (строковый аргумент`it` в обычном синтаксисе примера), поэтому единственная информация, которую читатель имеет о цели примера, это само ожидание.Следовательно,**Полезно использовать неявный предмет только тогда, когда контекст, вероятно, будет хорошо понят всеми читателями, и в действительности нет необходимости в описании примера**, Канонический случай - это проверка валидаций ActiveRecord с помощью совпадений musta:

Экспликация анонимная`subject` (определяется с`subject` без имени) немного лучше, потому что читатель может видеть, как это делается, но

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

Так,**законное использование явного анонимного`subject` или названный предмет очень редки**.

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

они определены с`let`/`let!` вместо`subject`/`subject!`они не устанавливают анонимных`subject` или позволить ожиданиям быть вызванными на это неявно.Когда их использовать**Полностью законно использовать`let` уменьшить дублирование среди примеров. Тем не менее, делайте это только тогда, когда это не жертвует ясностью теста.** Самое безопасное время для использования`let` когда`let` Назначение переменной полностью ясно из ее названия (так что читателю не нужно находить определение, которое может быть за несколько строк, чтобы понять каждый пример), и оно используется одинаково в каждом примере. Если что-то из этого не соответствует действительности, рассмотрите определение объекта в простой старой локальной переменной или вызов метода фабрики прямо в примере.

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

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

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

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

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

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



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

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



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

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

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