На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
Страницы: (6) « Первая ... 2 3 [4] 5 6  все  ( Перейти к последнему сообщению )  
> TDD vs не TDD
    Цитата applegame @
    Декларативное программирование красивое словечко не более того. Как коммунизм.

    ФП достаточно декларативно. Да даже в рамках традиционного ИП/ООП можно писать достаточно декларативно.
      Цитата korvin @
      – откуда мы знаем, что submit вообще вызовет accounts.load?
      – откуда мы знаем, что submit вызовет accounts.load с параметром sourceAccount.id?
      – откуда мы знаем, что submit не вызовет других методов accounts?

      Не знаю как в Java, а NSubstitute умеет проверять какие методы, в каком порядке, сколько раз и с какими аргументами были вызваны. Вообще не вопрос.

      Цитата korvin @
      Т.е. наличие параметра Accounts в публичном конструкторе — это часть контракта, публичная внешняя зависимость, а как именно используется экземпляр Accounts — это деталь реализации и «знание» этой детали в тесте — прямое нарушение инкапсуляции.

      Никто не мешает тебе изменить контракт на
      ExpandedWrap disabled
            public void submit(Accounts accounts, Request r) {
                final var source = accounts.load(r.source);
                final var destination = accounts.load(r.destination);
         
                validate(source, destination, r.amount);
                final var transaction = Transaction.fresh(r.source, r.destination, r.amount);
                transactions.store(transaction);
                notifyUsers(source, destination, transaction.id);
            }

      :) Просто разработчику было лень пихать accounts в каждый вызов :)


      Цитата korvin @
      Ни одной внешней зависимости с полным сохранением функциональности.

      Да брось! Теже яйца, только в профиль :) Теперь тебе надо мокать Request и точно также мокать 2 аккаунта ;)
        Цитата Wound @
        Зачем это делать?

        Интеграционный тест: правильно ли твой калькулятор пользуется логгером. =)
          Цитата korvin @
          Интеграционный тест: правильно ли твой калькулятор пользуется логгером. =)

          Это если речь идет о интеграционном тесте, он же пишет юнит тест.
            Цитата korvin @
            ФП достаточно декларативно.
            Да ни фига, просто маскируют императивность монадами да хвостовыми рекурсиями. И в конечном счете все те же рефакторинги, тесты и косяки. Так уж сложилось, что наш физический мир императивен, поэтому копни любую декларативность и под ней будет архитолстенный слой махровой императивщины.
            Сообщение отредактировано: applegame -
              Цитата Wound @
              Зачем это делать? Проверить правильно ли разработчики логгера его написали?

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

              PS: у нас есть список строк по которому идет поиск ошибок в логах. Если изменяется выводимая в лог строка, то надо и этот список проапдейтить. Проверка контента в данном случае работает на ура. Правда должен признать, что это скорее прихоть шефа :D Он хочет когда-нибудь достичь дзена и вручить этот список клиентам, чтобы они сами научились локализовывать проблемы.
                Цитата Fester @
                Не знаю как в Java, а NSubstitute умеет проверять какие методы, в каком порядке, сколько раз и с какими аргументами были вызваны. Вообще не вопрос.

                Да вопрос не в этом, как «технически» узнать. Mockito тоже всё это умеет. Вопрос в том, какого чёрта мы это как бы знаем, это деталь реализации, которую юнит-тест знать не должен.

                Цитата Fester @
                Никто не мешает тебе изменить контракт на

                Это никак не решает проблему: в интерфейсе Accounts десяток методов, метод submit использует только один из них. А может два, а может только при каких-то условиях. Об этом ничего не сказано в сигнатуре метода (входных параметрах), поэтому и юнит-тест этих деталей знать не должен. А значит, мокать нужно не отдельные вызовы метода Accounts.load, а все методы Accounts, т.е. фактически делать не мок, а стаб. Либо в качестве зависимости нужно не Accounts указывать, а интерфейс, определённый в модуле Transfer и имеющий точно нужную сигнатуру, а ля
                ExpandedWrap disabled
                  interface AccountLoader {
                      Account load(Account.ID id);
                  }

                и его использовать в сигнатуре метода.

                Цитата Fester @
                Теперь тебе надо мокать Request и точно также мокать 2 аккаунта

                Не надо мне мокать Request, я же написал пример теста, где там мок?

                Добавлено
                Цитата Wound @
                Это если речь идет о интеграционном тесте, он же пишет юнит тест.

                А это ещё одна проблема с моками: их любители часто думают, что пишут юнит-тест, но фактически получают интеграционный =)

                Добавлено
                Цитата applegame @
                Да ни фига, просто маскируют императивность монадами да хвостовыми рекурсиями.

                Никто ничего не маскирует, все пишут декларативную функциональную композицию. =)

                Цитата applegame @
                Так уж сложилось, что наш физический мир императивен

                Нет, наши физические компьютеры имеют императивную модель, а мир чисто конкурентно-событийный.
                Некоторые императивщики, конечно, пытаются переписать историю, но физически она не меняется.
                  Цитата Fester @
                  В данном случае это просто пример В реальном мире это может быть не логгер, а, скажем, нужно совершить 3 попытки коннекта и потом кинуть исключение. Или убедиться, что какая-то функция была вызвана с опреденными параметрами.

                  Зачем три попытки коннекта тестировать юнит тестами? :blink:

                  Добавлено
                  Цитата korvin @
                  А это ещё одна проблема с моками: их любители часто думают, что пишут юнит-тест, но фактически получают интеграционный =)

                  Ну вот как в примере выше Fester и пишет UT с моками, тестирует коннекты и логеры и называет это UT.
                    Цитата korvin @
                    Вопрос в том, какого чёрта мы это как бы знаем, это деталь реализации, которую юнит-тест знать не должен.

                    Так и во втором варианте надо знать детали :) Ну или можно не знать детали и мокать все, но тогда это будет, как ты сказал стаб :)


                    Цитата korvin @
                    Не надо мне мокать Request, я же написал пример теста, где там мок?

                    Я не силен в Java, так что заранее прошу прощения, но:
                    ExpandedWrap disabled
                          public Response submit(Request r) {
                              validate(r);
                              return transaction(r);
                          }
                       
                          private void validate(Request r) {
                              checkCompliance(r);
                              checkBalance(r);
                          }
                       
                          private void checkCompliance(Request r) {
                      // исходя из твоей логики, ты ничего не должен знать о реализации, а значит тебе придется мокать все проперти и методы как у source, так и у destination.
                              if (r.source.val().hasSameOwnerAs(r.destination.val())) {
                       
                                  return;
                              }
                      // тут ты вызываешь заклушку, т.е. это таки Mock-объект от Request'а
                              r.checkCompliance.val();
                          }
                       
                          private void checkBalance(Request r) {
                      // canWithdraw - еще одна функция, которую ты забыл мокнуть в своем тесте :)
                              if (r.source.val().canWithdraw(r.amount)) {
                                  return;
                              }
                      // надеюсь предусмотрен тест сценарий при котором будет вызывать это исключение... ну да, придется как-то иначе мокать canWithdraw, но что поделать?
                              throw new InsufficientFunds();
                          }
                       
                          private Response transaction(Request r) {
                      // ой, еще и Transaction надо мокнуть.
                              final var transaction = Transaction.fresh(r.source.val().id, r.destination.val().id, r.amount);
                      // а у source и destination еще и owner надо мокнуть, нет, зная реализацию Response мы понимаем, что null там вполне прокатит, но мы же исходим из того, что реализация нам не известна ;)
                              return new Response(
                                      transaction,
                                      new Response.Notification(r.source.val().owner, transaction.id, "withdraw"),
                                      new Response.Notification(r.destination.val().owner, transaction.id, "top up")
                              );
                          }


                    Как видишь Request придется тебе мокать целиком и полностью... ну или делать из него стаб. Тут я не хочу обсуждать как правильно это все называть. Как видим, ни от каких зависимостей ты не ушел, а реализацию тебе надо знать чтобы не мокать то, что не нужно в данном тесте.
                      Цитата korvin @
                      Никто ничего не маскирует, все пишут декларативную функциональную композицию. =)
                      Ага, пользуясь тем, что аргументы функции вычисляются гарантированно раньше самой функции. Даже вон do-нотацию придумали, чтобы упростить маскировку.
                      Цитата korvin @
                      Нет, наши физические компьютеры имеют императивную модель, а мир чисто конкурентно-событийный.
                      Наш мир, в первую очередь, причинно-следственный, и поэтому императивная модель куда ближе к этому миру, чем декларативная. Невозможно сварить борщ не составив последовательность действий. Даже если ты просто собираешь домик из готовых кубиков, ты не можешь начать строительство с крыши.
                      Сообщение отредактировано: applegame -
                        Цитата Wound @
                        Зачем три попытки коннекта тестировать юнит тестами?

                        Ну есть скажем требование: "в случае неудачного соединения N-раз повторить повторить попытку, после чего сообщить пользователю об ощибке". Вполне себе нормальный сценарий, который тоже можно протестировать.
                          Цитата Fester @
                          Так и во втором варианте надо знать детали

                          Какие?

                          Цитата Fester @
                          Как видишь Request придется тебе мокать целиком и полностью...

                          Не вижу, зачем? Это pure data, там нечего мокать. Если ты про canWithdraw, то это простой чистый метод, зачем его мокать? Всякие БД и прочие внешние сервисы мокают из-за сайд-эффектов и из-за того, что поднимать БД/внешний сервис для каждого теста — крайне медленно.
                          Но можно canWithdraw вынести в Request как Lazy<Boolean>-поле, и снова мокать ничего не надо.

                          Цитата Fester @
                          Как видим, ни от каких зависимостей ты не ушел

                          Я их сделал явными и ограниченными.

                          Цитата Fester @
                          а реализацию тебе надо знать чтобы не мокать то, что не нужно в данном тесте.

                          Не надо, мне нужно знать только тип входных данных (Request) и тип выходных данных (Response), которые полностью описывают всё, что нужно.

                          Цитата applegame @
                          Ага, пользуясь тем, что аргументы функции вычисляются гарантированно раньше самой функции.

                          Что?

                          Цитата applegame @
                          Даже вон do-нотацию придумали, чтобы упростить маскировку.

                          Нет, не для этого.

                          Цитата applegame @
                          Наш мир, в первую очередь, причинно-следственный, и поэтому императивная модель

                          Не применима, т.к. позволяет менять уже существующие причинно-следственные события, когда в реальном мире они не меняются, только порождаются новые. Чисто. Функционально.

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

                          Эти аналогии вообще к чему? По-твоему функциональные программы пишут на лету, в рантайме? Программа и есть описание процесса, выполненное в той или иной нотации/модели.

                          Цитата Fester @
                          Ну есть скажем требование: "в случае неудачного соединения N-раз повторить повторить попытку, после чего сообщить пользователю об ощибке". Вполне себе нормальный сценарий, который тоже можно протестировать.

                          Ну вот смотри, D_KEY, вместо того, чтобы декомпозировать код и вынести логику retry в отдельный RetriableConnection с настраиваемой политикой, отдельно и независимо протестированную, Fester решил накостылять сомнительные тесты прям над бизнес-логикой, сохранив её сложность и зафиксировав эту сложность в спецификации (тесте). Чё-т не очень ему TDD помогает делать код/архитектуру лучше.
                            Цитата applegame @
                            В жопу этот TDD, один хер реальное тестирование все равно происходит вручную в QA отделах.

                            Да, давайте завалим QA отдел непротестированным говном, у них ведь мало работы на регрессе и проверке новой функциональности :lol:
                            Наличие дополнительного ручного тестирования никак не отменяет необходимость автоматических тестов на разных уровнях.
                            А TDD - это вообще про написание кода больше :)

                            Цитата
                            но в подавляющем большинстве не критических для жизни людей проектов все именно так.

                            Да, там еще, как правило, есть разные процедуры сертификации, а иногда и системы испытаний. Это никак не отменяет важность автоматического тестирования. Я бы даже сказал наоборот.
                            Более того, когда такое ручное тестирование находит ошибку, то по возможности нужно добавить автоматические тесты на это. Люди в следующий раз могут пропустить эту ошибку или она может не воспроизвестись, например.
                            Прогоны в CI позволят получить более надежную систему как раз :)
                              Цитата korvin @
                              Что?
                              Декларативность не подразумевает вообще никакой последовательности действий. Ты объявил какой результат желаешь получить и условия его получения и опа все волшебно само-собой сложилось. Красота.
                              Цитата korvin @
                              Не применима, т.к. позволяет менять уже существующие причинно-следственные события,
                              Каким образом императивная модель позволяет менять существующие события?
                              Цитата korvin @
                              когда в реальном мире они не меняются, только порождаются новые. Чисто. Функционально.
                              Я не знаю в каком реальном мире ты живешь, но явно не в этой Вселенной. :D Допустим у меня есть стул и я его покрасил, в реальном мире у меня есть только покрашенный стул, в мире ФП у меня остался и покрашенный и непокрашенный. Чудеса в решете :) ФП переносит объекты из прошлого в настоящее. Машина времени прямо. :)

                              Добавлено
                              Цитата D_KEY @
                              Наличие дополнительного ручного тестирования никак не отменяет необходимость автоматических тестов на разных уровнях.
                              А TDD - это вообще про написание кода больше
                              Ну да. Я не против автоматического тестирования вообще, я скорее разочарован в TDD, никак не помогает в конечном итоге, скорее мешает. Особенно если проект не очень крупный.
                              Сообщение отредактировано: applegame -
                                Цитата korvin @
                                Чё-т не очень ему TDD помогает делать код/архитектуру лучше.

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

                                Кстати, обе стороны могут оказаться правыми в том смысле, что если человек не обладал навыками декомпозиции и пр., а начитавшись про TDD и начав его применять, стал об этом задумываться, то естественно он получить улучшения, а потом будет считать, что именно TDD ему помог. Хотя дело может быть исключительно в том, что он в принципе стал задумываться о тех вещах, о которых раньше не думал.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (6) « Первая ... 2 3 [4] 5 6  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0620 ]   [ 16 queries used ]   [ Generated: 24.04.24, 13:46 GMT ]