Распространенным инструментом проверки утверждений является метод toBe(). В сочетании с методом ожидания этот метод можно использовать для проверки того, что полученное значение равно значению, переданному в toBe().

Для тестирования примитивных типов данных, таких как укусы и целые числа, это прекрасно работает, но быстро разваливается при тестировании объектов и функций. Почему массив с теми же элементами, что и другой массив, не соответствует утверждению toBe()? Чтобы понять это, мы должны сначала погрузиться в темы изменяемых и неизменяемых объектов, а также оператора строгого равенства.

В чем разница между изменяемыми и неизменяемыми объектами? Во-первых, какие объекты считаются изменяемыми или неизменяемыми? Неизменяемые объекты включают строки и числа и копируются по значению. Это означает, что всякий раз, когда строка или число копируются для создания новой переменной, эта новая переменная имеет свое собственное значение, которое не влияет на объект, из которого она была скопирована.

Чтобы привести пример этого, давайте посмотрим на следующий код:

Здесь вы можете видеть, что мы создаем переменную str1 и присваиваем ей строковое значение. Затем мы создаем новую переменную str2, которой присваиваем значение str1. После того, как мы переназначим новое значение для str1 и напечатаем как str1, так и str2, мы увидим, что две переменные содержат разные значения, несмотря на то, что str2 была создана из значения str1.

Давайте теперь посмотрим на те же операции, но на этот раз проделаем их с массивами:

В этом случае, когда мы меняем значения массива nums1, значения массива nums2 также меняются. Если строка для строки str2 не была затронута изменением, внесенным в строку str1, то почему затронуты массивы nums? Массивы nums затронуты, потому что они являются изменяемыми объектами. Изменяемые объекты, к которым относятся массивы, объекты и функции, присваивают копии своих значений по ссылке, а не по значению. Это означает, что все копии изменяемого объекта указывают на один и тот же элемент в памяти, и поэтому каждый раз, когда вы меняете одну из них, вы меняете значения для всех копий, которые ссылаются на эти значения.

Чтобы запомнить разницу между изменяемыми и неизменяемыми объектами, нам нужно помнить, что изменяемые объекты создают копии, ссылаясь на один и тот же экземпляр объекта, а неизменяемые объекты создают копии, создавая новый отдельный экземпляр объекта.

Теперь, когда мы разобрались с неизменяемыми и изменяемыми объектами, нам нужно рассмотреть операторы равенства. В программировании операторы равенства — это способ проверить эквивалентность двух переменных. В Javascript двумя основными операторами равенства являются «==» и «===».

Хотя эти два оператора выполняют одну и ту же базовую проверку, между операторами равенства «==» и «===» есть небольшие различия. Первое различие между двумя операторами — это проверка типа. Оператор равенства «==» строго не проверяет тип своих двух операндов, а вместо этого принуждает их к тому, чтобы они имели один и тот же тип данных. Оператор равенства «===» использует строгую проверку типа данных и возвращает false, если два элемента не имеют одного и того же типа. Давайте посмотрим, как это выглядит в действии:

Здесь мы видим, что первое выражение проходит успешно, потому что оператор «==» приводит строковые и целочисленные типы данных к эквивалентности и пропускает выражение. Однако строгий оператор «===» не работает с этим выражением, потому что он не будет принуждать типы данных и, таким образом, не будет работать выражение, основанное на разных типах данных.

Теперь, когда мы рассмотрели операторы равенства с неизменяемыми объектами, давайте исследуем изменяемые объекты. Ниже я покажу выражения, выполненные между двумя одинаковыми, но отдельно созданными массивами, а также массивом, являющимся копией другого массива:

Здесь мы видим, что выражения возвращают true или false в зависимости от ссылки на их значение. С первым выражением оператора равенства мы видим ложный возврат, потому что ссылки сравниваемых значений различны. Несмотря на то, что содержимое массивов идентично, экземпляры в памяти, на которые они ссылаются, различаются, поэтому выражение не проходит проверку значения.

Когда мы проверяем, эквивалентны ли исходный массив nums1 и копия nums3, мы обнаруживаем, что они возвращают истинное значение, потому что они оба имеют одинаковые значения и одинаковую ссылку в памяти. Очень важно знать, какую глубину равенства вы проверяете всякий раз, когда используете эти операторы равенства.

После рассмотрения неизменяемых и изменяемых объектов, а также некоторых операторов равенства мы, наконец, готовы поговорить о различиях между методами toBe() и toEqual().

Методом перехода для многих тестов является toBe(), так как он хорошо работает с примитивными типами данных. Это замечательно, если вы хотите проверить, соответствует ли возраст пользователя определенному числу или что у клиента достаточно денег на банковском счете, но что, если вы хотите проверить дублирующуюся запись? Использование toBe() для проверки объекта, представляющего пользователя, завершится ошибкой, если используемые вами записи являются дубликатами, хранящимися в отдельных экземплярах памяти. Это связано с тем, что toBe() использует глубокую проверку на равенство для передаваемых элементов и отклоняет два идентичных объекта с отдельными ссылками. (Также будьте осторожны при использовании toBe(), потому что, как и «===», он не будет приводить значения с разными типами данных).

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

Тестирование — очень важная часть процесса разработки программного обеспечения. Эффективное тестирование требует от инженеров уверенного владения своими инструментами. Я надеюсь, что после прочтения этой статьи вы лучше понимаете изменяемые и неизменяемые объекты, разницу между «==» и «===» и когда использовать toBe() и toEqual().

Ссылки

https://howtocreateapps.com/mutable-and-immutable-types-in-javascript-with-examples/#:~:text=So%20what%20are%20mutable%20and,primitive%20types%20what%20are%20immutable .

https://jestjs.io/docs/en/expect#toequalvalue

https://benmccormick.org/2016/06/04/what-are-mutable-and-immutable-data-structures-2