В чем разница deep equal и обычного equal в тестах и как их использовать
Что проверяют
Понимаете ли вы разницу между сравнением по ссылке и сравнением по содержимому и какую проверку брать в автотесте. Следом обычно дают пример с вложенным объектом или массивом и просят сказать, упадёт тест или нет.
Как отвечать
Начните с двух видов равенства:
- по ссылке: равны, только если это один и тот же объект в памяти. В JavaScript это
===иObject.is(), в JesttoBe(), в Java==для объектов иassertSame(), в Pythonis; - глубокое, по значению: равны, если совпадают структура и значения на всех уровнях вложенности. В Jest это
toEqual()иtoStrictEqual(), в Chaideep.equal, в Node.jsassert.deepStrictEqual(), в Python==у словарей и списков, в JavaassertEquals()при корректномequals()илиusingRecursiveComparison()из AssertJ.
Два объекта { a: 1, b: { c: 2 } }, созданные отдельно, не равны по ссылке, но глубоко равны: toBe() на них упадёт, toEqual() пройдёт.
Нюансы Jest: toEqual() игнорирует свойства со значением undefined и не сравнивает классы объектов, а toStrictEqual() учитывает и то и другое. Для проверки части ответа API подходят toMatchObject() и expect.objectContaining(), тогда тест не падает из-за новых полей вроде createdAt.
Когда что брать: сравнение по ссылке для примитивов и проверки «вернулся тот же экземпляр» (кэш, синглтон); глубокое для тел ответов, DTO и состояния после операции; частичное сравнение или JSON Schema для ответов с динамическими полями.
Где спотыкаются
Сравнивают объекты через JSON.stringify(). Порядок ключей влияет на результат, undefined и функции теряются, Date превращается в строку, а сообщение об упавшем тесте нечитаемо.
Используют toBe() для объектов и массивов и не понимают, почему тест с одинаковым на вид содержимым падает.
Путают поверхностное равенство со ссылочным. Shallow equal сравнивает свойства верхнего уровня по ссылке. Это отдельный третий вариант, его использует React в React.memo и PureComponent, и он не синоним ===.