Pull to refresh
22
0
Игорь Чулинда @Igmat

Пользователь

Send message

Я конечно не специалист в криптографии, но мне казалось, что настоящая случайность требует специализированного железа, а всё остальное, всё равно, так или иначе детерминировано.

  1. Тут ещё можно добавить TypeScript, хотя этот инструмент тоже совсем не про тестирование.
  2. Многие интеграционные тесты похожи на смоки.
  3. Так BaseT, в каком-то смысле, именно про это. Более того в нём уже даже есть функция генерации использований (команда scaffold, правда она совсем сырая и требует ещё очень много доработок).

Так что присоединяйтесь, если я ваши мысли правильно понял :)

Это явно не кейс для юнит-тестирования. Либо же кластер должен быть мокнут.

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


Суть в том, что без юнит-тестов написание кода нельзя считать завершённой, потому что "не протестированный код == нерабочий код".

С этим я полностью согласен, но зачем ещё пару дней его обвешивать юнит-тестами, если можно создать инструментарий, который будет требовать на это только пару часов. И то, если делать это пост-фактум, хотя можно делать и паралельно в 3 окнах:


  1. код
  2. использование кода, что можно назвать входными данными
  3. постоянно обновляемый результат.

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

Потому что всё равно нужно добавлять разный мусор и явно делать expect(..).toMatchSnapshot()


import React from 'react';
import Link from '../Link.react';
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="http://www.facebook.com">Facebook</Link>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

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

4-ое издание PMBOK, в котором впервые отошли от каскадной модели в сторону гибридной (то есть признали достижения гибких методологий) вышло только в 2008 году.
Так что ИМХО всё время ДО этого момента всё ещё «Золотой век» водопада, несмотря на то, что итеративные методологии использовались и задолго до этого, но это не было так распространенно.

Да, речь шла о первом фреймоврке для JS, наверное стоит уточнить в самой статье.


В самой статье я ссылался на Кента Бека ("переоткрыл" TDD в 1999) и эту любопытную заметку про возраст TDD.
Само же юнит-тестирование я считал от появления TAP в 1987 т.е. даже раньше чем указанный вами 1989, но суть была не в полной энциклопедической достоверности, а в том, что бы показать, что эти подходы существуют уже очень давно (дольше, чем я живу, например).


А теперь от истории к действительно важному:)


Прочитал тот ваш прошлогодний коммент, жаль не могу лайк поставить т.к. "срок голосования истёк" :(
В целом согласен, поэтому и написал следующее:


Значит TDD всё-таки ошибочно? — Нет, TDD не ошибочно.
Оно указывает правильно направление и поднимает важные вопросы. Мы просто должны переосмыслить и изменить способ его применения.

И в BaseT я хочу добится не использования правила "test first", а просто написания теста и кода по сути паралельно, что, кстати, вроде довольно неплохо будет ложиться на те наукоемкие примеры, что вы приводили у себяю

Спасибо за такой обстоятельный и позитивный комментарий:)


BDD в целом и кукумбер в частности мне были довольно интересны, но в целом это поход в другую сторону — и я не считаю это неправильным, просто другим.


BDD это движение от юнит-тестов к более высокому уровню абстракции, что в целом очень интерестно и делает поведенческие тесты настоящей формализацией требований, в чём ИМХО кроется огромное кол-во разных плюсов. Но…
BDD это процесс, к тому же даже в большей степени чем TDD, возможно даже в большей степени чем какой-нибудь Agile/Scrum. Это не плохо и не хорошо, просто требует достаточно серъёзных организационных затрат + подключение к процессу, как минимум, BA т.е. это всё уже выходит далеко за рамки просто инструмента для разработчиков.


В то время как BaseT — это, наоборот, движения от процесса (TDD) к простому, как угол дома, инструменту. И да в BaseT есть амбиции на создание в том числе и чего-то близкого к live documentation (таски #11 и #14), если я правильно понял о чём этот термин.


К тому же, если BaseT + другой фреймоврк для юнит-тестирования (типа Jest/Mocha/Tape) — это ИМХО глупость и они скорее будут мешать друг другу, то BaseT + BDD (тот же кукумбер), вполне могут дополнять друг друга.

Хреново может быть написан как код, так и тест. Проблема в том, что при существующих инструментах правила написания кода отличаются от правил написания теста, в то время, как в BaseT, я стараюсь свести эти правила воедино.

Тут полностью согласен. Хотя ИМХО тестирование чистых функций в BaseT проще, чем в других инструментах, а по поводу сайд-эффектов:


  1. Для pixi.js это как раз и было проблемой, потому что главный результат рендеринга их DisplayObjectа это и есть побочный эффект. Но посольку я понимал, что подобное будет встречатся, был предусмотрен API для специфических резолверов и в итоге реализация pixi-resolver была довольно простой и потребовала совсем небольшое кол-во кода.
    К тому же, в планах реализовать резолверы для всех популярных либ (для реакта уже есть, ангуляр в ближайшей перспективе)
  2. В планах так же side-effects collectors API + реализации самых распростронённых кейсов, типа сериализация результирющего DOM или изменений в файловой системе/базе данных.

Удобного АПИ для моков пока нет (хотя никто не мешает делать их руками), но оно в процессе.

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

Да, я в курсе про snapshot testing. Но это узкоспециализорованная фича для конкретного случая с реактом.


Как раз в подходе с baseline есть четкое определение ожидаемого результата. Как я уже упоминал любой тест можно переписать используя только equals/deepEquals и в целом такой подход очень правильный даже для уже популярных инструментов. Тот же Tape собственно ограничился необходимым минимумом для такого тестирования.


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


И так довольно часто видел как пишутся тесты (общая структура), потом пишется нетривиальный код, берётся его оутпут, оценивается на корректность разработчиком, и вставляется в тест, как ожидаемое значение. Та и сам так делал. Зачем это делать руками, если это может сделать софт, а нам нужно только принять или не принять расчитанное значение?

если это происходит "всё время" — скорее всего это признак того, что разработчик ещё не научился нормально писать тесты

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


Проблема именно в этом отношении — тесты это такой же код, их тоже надо писать достаточно чисто, рефакторить...

Мы всё время создаем инструменты, которые ускоряют процесс разработки, почему вдруг мы не должны оптмизировать время на тестирование?
Юнит-тесты (именно они, без учёта поведенческих) сами по себе (без кода, который они тестируют) не приносят никакой пользы. От них появляется смысл только тогда, когда есть код.
Относится к тестам так же как и к коду имеет смысл только при работе над поведенческим/интеграционным/нагрузочным тестированием, в других случаях затраты на них просто никогда не окупятся.
Именно поэтому юнит-тесты часто пропускаются в реальных проектах, я же пытаюсь сделать их частью процесса разработка, давая максимально возможный value от тестов, при минимальных трудозатратах.


TDD не требует чтобы эту задачу поручали разработчику, который не умеет писать тесты.

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


Вообще, лично я не сторонник TDD...

Судя по всему у нас кардинально разный опыт в разработке/тестировании. Я никогда не видел качественного покрытия в 80%-90% без использования TDD или выделения отдельной фазы (минимум в пару месяцев, в зависимости от размера проекта) на покрытие кода тестами, без внедрения нового функционала. Последний вариант я встречал вообще только 1 раз т.к. клиент зачастую не готов платить за что-то абстрактное без чёткого понимания ответа на вопрос "где деньги?".


В целом одна из идей, в том что бы сделать TDD менее формальным, спустить его с уровня процесса до уровня инструмента так, что бы тест писался вместе с кодом и разделение на написание теста/написание кода потеряло смысл.

  1. ЛЮБОЙ тест можно привести к использованию equals и deepEquals. Если нужна именно логика "будет получено от 2-х до 5-ти значений, среди которых должно быть значение X", то вы можете экспортировать булевое значение, которое принимает true именно в таких условиях, и получить тест для baset.
  2. Такой тест выглядит весьма странно, недетерминированное поведение модуля это уже запашок. Код, который возвращает разные значения (возвращение одних и тех же результатов в разном порядке — это по сути возвращение разных результатов) для одних и тех же входных параметров, потенциально ведёт к огромному количеству ошибок. Поэтому ИМХО их либо нужно синкать, либо разбивать на отдельные модули, либо… Ещё миллион вариантов, но они уже зависят от конкретной задачи.
Ничего страшного:)
Технически я статью сначала писал на английском, а потом переводил, так что это могло повлиять на ощущения от прочтения.
  1. Это обеспечит стабильность кода, а не требований. Чем выше уровень абстракции конкретного модуля, тем сильнее требования к нему зависят от требований бизнеса. И я не считаю, что такие модули должны тестироваться только с помощью BDD, так как для последнего требуется ещё на порядок больше усилий, включая организационные.
  2. Да, собственно о том и раздел. Не стоит ожидать от TDD того чего оно не может дать.
  3. А ещё они требуют времени на поддержку. И есть огромное количество кейсов, когда вложенное время на успевает отбиться, просто потому что тесты переписываются всё время. Я не говорю, что это повод не писать тесты, но это повод оптимизировать время, которое на них затрачивается.
  4. Круто, что в Go это есть их коробки, но в JS для этого нужен инструмент, который я представил.

считается что любой программист автоматически умеет писать тесты — а это не так

Этого требует TDD — тест пишет разработчик, который реализовывает задачу. Я согласен, что писать правильные тесты сложно, поэтому и предлагаю инструмент, для которого дополнительные знания не нужны — просто используй код, который написал.

Тут есть два момента:


  1. Сейчас действительно сложно тестить не детерминированные вещи — для этого ведётся работа над тасками #16 и #17, что бы дать возможность спокойно мокнуть рандом или тот же Date.now без лишних телодвижений.
  2. Если речь идёт о собственном генераторе псевдослучайных чисел, то у него зачастую есть сид значение, которое его детерминирует.
2

Information

Rating
Does not participate
Location
Lublin, Польша
Date of birth
Registered
Activity