Здравствуйте, ·, Вы писали:
·>Это разница между хрупкими тестами, которые тестируют детали реализации и полезными тестами, которые тестируют аспекты поведения.
"Аспекты поведения" можно зафиксировать e2e-тестами только в исчезающе малом количестве случаев.
·>Как проверить что к _любому_ запросу. В твоём _тесте_ проверяется только для одного конкртетного запроса с одним из заданных в тесте criteria.
Все остальные варианты исключаются дизайном функции построения запроса.
·>Из привёдённых снипппетов кода я вижу что именно библотечный и по-другому вряд ли может быть, т.к. код получится совсем другим.
Ну ок, минус один тест.
·>Да банально скобочки забыты вокруг ?: — ошиблись в приоритете операций, должно было быть (someMagicalCondition(criteria) ? buildOptimizedQuery(criteria) : buildWhere(criteria)).addLimit(pageSize).
Повторюсь: внесение скобочек и ветвлений в текст функции buildQuery запрещено. Все вот эти вот фантазии про buildOptimizedQuery нужно вносить внутрь buildWhere.
Запрет реализуется орг.мерами — от обучения разрабочиков, до код ревью и отбора прав на соответствующую ветку репозитория.
Как вариант (если у нас достаточно развитая платформа) —
сигнатурой функции, которая обязуется возвращать ILimitedQueryable<...>.
·>Ведь проблема в том, что мы не описали в виде теста ожидаемое поведение. А тестирование синтаксиса никакой _новой_ информации не даёт, синтаксис и так виден явно в диффе.
·>В этом и суть что с т.з. _кода теста_ — проверять наличие addLimit или size()==10 — даёт ровно те же гарантии корректности лимитирования числа записей. Но у меня дополнительно к этому ещё некоторые вещи проверяются и нет завязки на конкретную реализацию, что делает тест менее хрупким.
У вас есть завязка на конкретное наполнение тестовых данных. И это делает код ваших тестов значительно более медленным, и примерно настолько же хрупким.
Вот у вас там кто-то подпилил код репозитория, и теперь применяются чуть более строгие критерии; параллельно в одной из комбинаций вы забыли добавить лимит. Тест по-прежнему зелёный, т.к. вернулось столько же записей, вот только на данных прода там поедет половина базы.
Вы, если я правильно понял, предлагаете это предотвращать просто просмотром синтаксиса при диффе. Ну так тогда все ваши аргументы начинают работать против вас.
·>Верно. Т.е. оба подхода при прочих равных этот аспект проверяют ровно так же. Но твой тест покрывает меньше аспектов.
Ну так это сделано намеренно. Потому что те "дополнительные аспекты", которые тщится проверять ваш тест, не нужно проверять в
каждом из юнит-тестов.
Если, скажем, вы боитесь напороть в критериях фильтров, перепутав != и == (всякое бывает), то да, можно проверить этот аспект.
Но тут же идея как раз в том, что stateless подход позволяет нам распилить сложный запрос на несколько фрагментов, и
каждый протестировать по отдельности.
В вашем подходе ничего подобного не получится — есть чорный ящик репозитория, в который мы кидаем какие-то параметры, и он нам что-то возвращает. Из того, что для параметров A и для параметров B возвращаются корректные результаты, никак не следует то, что корректными будут результаты для комбинации A & B. В моей практике косяки склеивания частей запроса встречались гораздо чаще косяков перепутывания < и >.
А вопросы строгости/нестрогости неравенств упираются не столько в навыки программиста, сколько в интерпретацию требований заказчика. Ну, там, когда мы запрашиваем отчёт с 03.03.2024 по 03.03.2024 — должны ли в него попасть записи от 03.03.2024 0:00:00.000? Если да, то должна ли в него попасть запись 03.03.2024 12:30:05? Это — работа аналитика, который и будет писать в спеку конкретные < end, <= end, или там < end+1.
Неспособность разработчика скопипастить выражение из спеки, да ещё и дважды подряд (в предположении, что тесты пишет тот же автор, что и основной код) — это какая то маловероятная ситуация.
·>Причём тут вредители? Я очень часто путаю == и != или < и > в коде. Поэтому ещё один способ выразить намерение кода в виде тестового примера с конкретным значением помогает поймать такие опечатки ещё до коммита. Может ты способен в сотне строк обнаружить неверный оператор или забытые строки приоритета, но я на такое не тяну.
Не, я тоже не тяну. Поэтому не надо писать код на сотню строк, где перемешаны операции склейки запроса и написания предикатов.
Надо есть слона по частям. В одиночном предикате, где есть ровно одно сравнение, вы вряд ли допустите такую опечатку.
А если вы пишете всё простынкой SQL — ну, удачи, чо. Про такой код можно только молиться. Я в своей карьере такого встречал (в основном до 2010), и во всех тех местах были недотестированные ошибки.
·>Поэтому мне надо это дело запустить и просмотреть на результат для конкретного примера.
·>Так ведь ревью делается и для тестов, и для кода. Мне по коду теста сразу видно, что find(10).size() == 10 — правильно. А вот уверено решить что должно быть "rownum > 10", "rownum <= 10" или "rownum < 10" — лично я не смогу, тем более как ревьювер большого PR.
Всё правильно, поэтому нефиг писать rownum <=10. Надо писать .addLimit(10). Его 1 (один) раз тестируют, и потом тысячи раз пользуются, полагаясь на его корректность.
А вы сначала создали себе трудности, использовав неудачную архитектуру, а потом пытаетесь их преодолеть при помощи медленных и неполных тестов.
·>Какую сложную функцию? Вы просто переписали кривой код на прямой. Тесты тут причём?
Сложная функция, которая превращает Criteria в набор записей. У вас это даже не функция, а объект — потому что у него есть внешние stateful dependencies.
А у нас это функция, которая состоит из цепочки простых функций, каждая из которых легко тестируется.
В вашем подходе так сделать невозможно — вы не можете взять два метода из репозитория, скажем findUsersByMailDomain() и findUsersByGeo(), и получить из них метод findUsersByMailDomainAndGeo().
Именно в силу выбранной архитектуры.
·>Я такого не предлагаю.
Да ладно!
·>Да пожалуйста, если получится.
Я не вижу причин, по которым это не получится. Вы же даже стремиться к этому отказываетесь, потому что пребываете в иллюзии невозможности
·>Код и тесты обычно пишет один человек. Или вы парное программирование используете?
Нет. Обычно используется всё же разделение между QA и Dev.
·>Если код функции котороткий, то значит у тебя такхи функций овердофига. И в каждой из паре операций можно сделать очепятку.
Поскольку отлаживаются и тестируются эти функции по отдельности, шансов пропустить опечатку гораздо ниже, чем когда у нас один метод на пятьсот строк, с нетривиальным CFG и императивными stateful зависимостями.