<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840228</guid>
        <pubDate>Sat, 10 Oct 2020 13:34:51 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840228</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3840071'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2020-10-06T23:40:46+03:00">06.10.20, 20:40</time></span><div class='quote '>Я чего ты ждёшь-то собсвтенно?</div></div>Я жду когда<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3839968'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2020-10-05T16:32:23+00:00">05.10.20, 16:32</time></span><div class='quote '>нейронки выйдут из эмбрионального состояния, и всякоразные Плюсы с Питонами уйдут в нишу автокода.</div></div>Ты же сказал &quot;погоди&quot;, вот я и спрашиваю долго ли еще погоджать?]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840226</guid>
        <pubDate>Sat, 10 Oct 2020 11:27:59 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840226</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3840071'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2020-10-06T20:40:46+00:00">06.10.20, 20:40</time></span><div class='quote '>Я лично слабо себе представляю создание тестов без проверки их на реализованном поведении, т.к. при наличии фейла и следовательно для выявления его причины легче разобраться в чёткой логике, описанной формальным языком с формальной грамматикой, чем в его формальном описании на нечётком человеческом с множеством потенциальных неточностей, неоднозначностей и недосказанностей и местами противоречий, что не были замечены на <span class="tag-color tag-color-named" data-value="gray" style="color: gray">извиняюсь</span> спринтах.</div></div><br>
Я попробовал TDD на своем маленьком проекте, пока все очень хорошо пошло. Но я так только несколько часов покодил пару недель назад, забросил пока :( <br>
Надеюсь, что вернусь на неделе к этому, посмотрим, как оно дальше пойдет.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>при наличии фейла и следовательно для выявления его причины легче разобраться в чёткой логике, описанной формальным языком с формальной грамматикой, чем в его формальном описании на нечётком человеческом с множеством потенциальных неточностей, неоднозначностей и недосказанностей и местами противоречий, что не были замечены на <span class="tag-color tag-color-named" data-value="gray" style="color: gray">извиняюсь</span> спринтах.</div></div><br>
Мы, кстати, на работе сейчас пробуем BDD подход, к user story сразу пишем BDD-сценарии, которые потом используем в автотестах для стори. Вроде хорошо пошло. Это так же помогает и в процессе PBR (на грумингах и не только).<br>
Попробуем несколько спринтов, потом решим, будет ли с этим жить.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840071</guid>
        <pubDate>Tue, 06 Oct 2020 20:40:46 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840071</link>
        <description><![CDATA[Qraizer: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838219'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:51:18+00:00">03.09.20, 08:51</time></span><div class='quote '>Ну да. Я не против автоматического тестирования вообще, я скорее разочарован в TDD, никак не помогает в конечном итоге, скорее мешает. Особенно если проект не очень крупный.</div></div>И ещё особенней, если очень крупный. Оракл вон наособничался, когда читал, волосы даже в интимных местах шевелились. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-06T20:44:08+00:00">06.10.20, 20:44</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838230'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:53:43+00:00">03.09.20, 09:53</time></span><div class='quote '>Вот есть скажем требование что размер формы должен быть 100x200, вполне себе нормальный сценарий, который тоже можно протестировать. Или скажем &quot;в случае неудачного соединения N-раз должно выскакивать окно - &quot;Подключение невозможно, проверьте параметры сети&quot;, которое должно располагаться по центру экрана&quot;. Вполне себе нормальный сценарий, который тоже можно протестировать. Ага?</div></div>Всё просто: тестировать надо всё, что написано в спецификациях. Ничего там не заявленного, тестировать не надо. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-06T20:51:42+00:00">06.10.20, 20:51</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838334'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T08:00:14+00:00">05.09.20, 08:00</time></span><div class='quote '>Вот начинаем мы какую-то новую штуку кодить по TDD. Мы начинаем же с самых высокоуровневых задач? Т.е. сначала пишем тест на высокоуровневую задачу, верно? Потом, при развитии, проверяемая такими тестами функциональность в любом случае будет раскидана по нескольким юнитам. Так вот вопрос, эти более ранние тесты становятся интеграционными? Ведь у каждого юнита появится свой тест.</div></div>Хороший вопрос. Готовый функционал лучше всего покрывается тестами снизу вверх. Пишешь юниты на каждый чих, интеграцией проверяешь их ...э-э-э, интеграцию. Разработка обычно идёт так же, а вот проектирование в обратном направлении. Я лично слабо себе представляю создание тестов без проверки их на реализованном поведении, т.к. при наличии фейла и следовательно для выявления его причины легче разобраться в чёткой логике, описанной формальным языком с формальной грамматикой, чем в его формальном описании на нечётком человеческом с множеством потенциальных неточностей, неоднозначностей и недосказанностей и местами противоречий, что не были замечены на <span class="tag-color tag-color-named" data-value="gray" style="color: gray">извиняюсь</span> спринтах. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-06T21:03:26+00:00">06.10.20, 21:03</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3840060'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-10-06T16:02:16+00:00">06.10.20, 16:02</time></span><div class='quote '>И долго еще осталось погождать?</div></div>Я чего ты ждёшь-то собсвтенно? Итогов по их спору, что ли?<br>
По <strong class='tag-b'>Wound</strong>-у требуется один юнит на интерфейс калькулятора, ещё один на интерфейс логгера и отдельный интегрант на их композицию. Этого достаточно на все случаи жизни. Вообще все. Пока не изменятся спецификации интерфейсов, конечно. Сколько ты не будешь мутить их комбинаций, эти три теста всегда будут к ним применимы, и всегда будут адекватны. Любая отдельная реализация обязана будет проходить эти тесты, без вариантов. Откуда у <strong class='tag-b'>Fester</strong> там взялся зоопарк, я не имею ни малейшего понятия. Понятно, что отдельные реализации каждого из этих интерфейсов могут захотеть по-разному его расширить, и тогда на каждое такое расширение потребуется отдельный юнит, дополняющий, но не заменяющий, обобщённый юнит этого интерфейса. В итоге имеем: один общий юнит на каждый интерфейс, опциональный дополняющий его один частный юнит на каждую его реализацию и один интегрант на их композицию. Всё.<br>
Проблема лишь в том, что реализации пасскритериев (именно реализации пасскритериев, а не собственно пасскритерии) для каждой частной реализации общего интерфейса могут отличаться в связи с тесной связью с этой самой реализацией, что затруднит создание обобщённых юнитов. Но это же не проблема, ведь, так? Мы тут прогаммеры или куда?]]></description>
        <author>Qraizer</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840060</guid>
        <pubDate>Tue, 06 Oct 2020 16:02:16 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840060</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3839968'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2020-10-05T16:32:23+00:00">05.10.20, 16:32</time></span><div class='quote '>Вот погоди, нейронки выйдут из эмбрионального состояния, и всякоразные Плюсы с Питонами уйдут в нишу автокода.</div></div>И долго еще осталось погождать?  :)]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840054</guid>
        <pubDate>Tue, 06 Oct 2020 14:10:23 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3840054</link>
        <description><![CDATA[sergioK: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3839968'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2020-10-05T16:32:23+00:00">05.10.20, 16:32</time></span><div class='quote '>подход <strong class='tag-b'>Wound</strong> не просто правилен, он единственно праведно верный.</div></div><br>
Это чистой воды Aspect, вряд ли он это мог предложить,<br>
так что подходов уже как минимум два  ;) а подход назывется no coupling <br>
или  по народному private responsibility или has a, предложил его кажется кто то из Борланда году <br>
в 1993-1994, ох как Я люблю так много умных слов  ;) <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-06T14:23:50+00:00">06.10.20, 14:23</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838343'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T12:29:25+00:00">05.09.20, 12:29</time></span><div class='quote '>Осталось понять, как правильно писать интеграционные тесты в C++ :D</div></div><br>
Включать здравый смысл, и перестать разводить не нужные теории  ;)]]></description>
        <author>sergioK</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3839968</guid>
        <pubDate>Mon, 05 Oct 2020 16:32:23 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3839968</link>
        <description><![CDATA[Qraizer: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838170'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T04:21:42+00:00">03.09.20, 04:21</time></span><div class='quote '>По мне так декларативный код - утопия.</div></div>Вот погоди, нейронки выйдут из эмбрионального состояния, и всякоразные Плюсы с Питонами уйдут в нишу автокода. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-05T16:39:59+00:00">05.10.20, 16:39</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>Вводится дополнительный класс с дополнительной логикой.<br>
...</div></div>Не мути воду. Ты не такую задачу поставил. В том виде. как ты её поставил:<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838111'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:46:11+00:00">02.09.20, 09:46</time></span><div class='quote '>Ну вот представим, что у тебя есть 2 компоненты: калькулятор и логгер. Все действия калькулятора должны быть запротоколированы. Как должен выглядить идеальный юнит-тест суммы?</div></div>подход <strong class='tag-b'>Wound</strong> не просто правилен, он единственно праведно верный. Ты же сейчас путём волшебных ментальных манипуляций придумал новую задачу: придумать реализующую исходную задачу архитектуру, которую было бы удобно тестить. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-10-05T16:40:34+00:00">05.10.20, 16:40</time></span></span><br>
<span class="tag-color tag-color-named" data-value="gray" style="color: gray">P.S. Прочитал пока только половину темы.</span>]]></description>
        <author>Qraizer</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838344</guid>
        <pubDate>Sat, 05 Sep 2020 12:31:35 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838344</link>
        <description><![CDATA[korvin: Кстати, возможно, в интеграционном тесте лучше не мокать субкомпонент, или добавить к мокнуты ещё тесты с использованием реального инстанса субкомпонента, иначе некоторые изменения не отловятся тестами]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838343</guid>
        <pubDate>Sat, 05 Sep 2020 12:29:25 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838343</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838342'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T12:13:58+00:00">05.09.20, 12:13</time></span><div class='quote '>если ты делаешь инверсию зависимости для этого субкомпонента, то твой изначальный тест суперкомпонента нужно разбить на два:<br>
1) юнит-тест, который будет мокать/стабать интерфейс зависимости и проверять корректность входа/выхода суперкомпонента<br>
2) интеграционный, который также будет мокать/стабать интерфейс зависимости, но проверять само взаимодействие, т.е. например, убеждаться, что суперкомпонент при каком-то входе вызывает метод интерфейса зависимости, нужное количество раз с правильными параметрами</div></div><br>
Во, кажется это ответ на мой вопрос :) <br>
Осталось понять, как правильно писать интеграционные тесты в C++ :D <br>
А то я так понимаю теперь, что у меня всегда были юнит-тесты, которые пишут разрабы, и системные, которые пишут qa.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838342</guid>
        <pubDate>Sat, 05 Sep 2020 12:13:58 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838342</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838341'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T11:56:11+00:00">05.09.20, 11:56</time></span><div class='quote '>Но вопрос изначальных тестов. Они же исходят из высокоуровневых задач и будут проверять работу целиком</div></div><br>
Э, ты путаешь тёплое с мягким, тип проверки зависит от типа теста и не зависит от уровня тестируемого компонента в системе. Работу целиком проверяют end-to-end и системные тесты. Как только ты принял решение выделить из высокоуровневого модуля под-модуль, сначала ты должен поменять тесты соответствующим образом, в этом же суть TDD: любое изменение начинается с тестов, т.е. сначала нужно убедиться, меняется ли архитектура/требование, потом отразить изменения в тестах, если нужно и только потом — в реализации.<br>
<br>
Тут всё зависит от того, выносишь ты субкомпонент как внешнюю зависимость или оставляешь его деталью внутренней реализации суперкомпонента:<br>
<br>
– если ты делаешь инверсию зависимости для этого субкомпонента, то твой изначальный тест суперкомпонента нужно разбить на два:<br>
1) юнит-тест, который будет мокать/стабать интерфейс зависимости и проверять корректность входа/выхода суперкомпонента<br>
2) интеграционный, который также будет мокать/стабать интерфейс зависимости, но проверять само взаимодействие, т.е. например, убеждаться, что суперкомпонент при каком-то входе вызывает метод интерфейса зависимости, нужное количество раз с правильными параметрами<br>
<br>
- если ты не делаешь инвресию зависимости, просто выносишь часть кода суперкомпонента в субкомпонент и используешь последний как некую библиотеку, то объект субкомпонента будет инстанциироваться внутри суперкомпонента (если это не так и ты передаёшь экземпляр субкопонента в публичный конструктор супера, то это уже внешняя зависимость и тебе лучше сделать полноценную инверсию и перейти к первому случаю) и ни мокать, ни стабать ты его не можешь и не должен, он всё также остаётся деталью внутренней реализации и изначальный тест у тебя не меняется.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838341</guid>
        <pubDate>Sat, 05 Sep 2020 11:56:11 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838341</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838340'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T11:28:49+00:00">05.09.20, 11:28</time></span><div class='quote '>Ну, собственно, если у тебя правильная инверсия зависимостей, то высокоуровневый модуль полностью независим от низкоуровневых и ты можешь писать нормальные юнит-тесты для него )</div></div><br>
Это да. Но вопрос изначальных тестов. Они же исходят из высокоуровневых задач и будут проверять работу целиком. Соответственно, они должны будут или перейти на уровень интеграционных или, став юнит-тестами для самих высокоуровневых юнитов, перестанут проверять высокоуровневые задачи.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838340</guid>
        <pubDate>Sat, 05 Sep 2020 11:28:49 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838340</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838334'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-05T08:00:14+00:00">05.09.20, 08:00</time></span><div class='quote '>Так вот вопрос, эти более ранние тесты становятся интеграционными? Ведь у каждого юнита появится свой тест.</div></div><br>
Не обязательно, зависит от архитектуры. У тебя же высокоуровневая задача является некоторой композицией низкоуровневых, вот смотри, в моём примере, я переделал высокоуровневый сервис (относительно Accounts, Transactions, Compliance, Notifier) Transfer, чтобы он не включал зависимости внутрь себя, т.е. вместо<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Transfer</div><div class="code_line">&nbsp;&nbsp;+ Accounts</div><div class="code_line">&nbsp;&nbsp;+ Transactions</div><div class="code_line">&nbsp;&nbsp;...</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
получилось<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">Composer</div><div class="code_line">&nbsp;&nbsp;+ Transfer</div><div class="code_line">&nbsp;&nbsp;+ Accounts</div><div class="code_line">&nbsp;&nbsp;+ Transactions</div><div class="code_line">&nbsp;&nbsp;...</div></ol></div></div></div></div><br>
где Transfer хоть и реализует высокоуровневую логику посредством остальных компонентов, но расположен на том же (структурном?) уровне фактически.<br>
Composer в свою очередь может быть абстрактным и тривиальным и иметь свои юнит-тесты. Естественно, можно сделать и интеграционные тесты (они ж не взаимозаменяемы с юнит-тестами), а на самом-самом верхнем уровне ещё добавить функциональные/end-to-end/системные тесты. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-05T11:47:35+00:00">05.09.20, 11:47</time></span></span><br>
Ну, собственно, если у тебя правильная инверсия зависимостей, то высокоуровневый модуль полностью независим от низкоуровневых и ты можешь писать нормальные юнит-тесты для него )]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838334</guid>
        <pubDate>Sat, 05 Sep 2020 08:00:14 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838334</link>
        <description><![CDATA[D_KEY: Вопрос к практикам. Вот начинаем мы какую-то новую штуку кодить по TDD. Мы начинаем же с самых высокоуровневых задач? Т.е. сначала пишем тест на высокоуровневую задачу, верно? Потом, при развитии, проверяемая такими тестами функциональность в любом случае будет раскидана по нескольким юнитам. Так вот вопрос, эти более ранние тесты становятся интеграционными? Ведь у каждого юнита появится свой тест.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838319</guid>
        <pubDate>Fri, 04 Sep 2020 17:36:40 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838319</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838292'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T14:43:44+00:00">04.09.20, 14:43</time></span><div class='quote '>Функция, которая ничего не делает - это заглушка, т.е. фактически это и есть mock.</div></div><br>
Нет.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838292'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T14:43:44+00:00">04.09.20, 14:43</time></span><div class='quote '>Я уж как-нибудь обойдуть одним объектом, который полностью описывает &quot;пользователя&quot; и не буду убиваться из-за некоторой избыточности</div></div><br>
Любитель сильной связности. Понятно.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838292'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T14:43:44+00:00">04.09.20, 14:43</time></span><div class='quote '>В подавляющем случае как раз нет и в 99% случаев функция не использует все поля.</div></div><br>
Только в говнокоде.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838292'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T14:43:44+00:00">04.09.20, 14:43</time></span><div class='quote '>Просто из-за того, что никто не будет шлепать отдельный объект ради каждой функции.</div></div><br>
Просто убогие недоязычки не позволяют легко и просто описывать типы. Впрочем, на сегодняшний день из таких только Java осталась, да Pascal. На Джаве ты не пишешь, значит на Паскале?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838298'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T15:36:33+00:00">04.09.20, 15:36</time></span><div class='quote '>В данном тесте - последний параметр - это заглушка и, соответственно Request - это мок-объект.</div></div><br>
Нет. Request даже не объект.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838298</guid>
        <pubDate>Fri, 04 Sep 2020 15:36:33 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838298</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838294'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T15:09:29+00:00">04.09.20, 15:09</time></span><div class='quote '>Не совсем понял эту цитату. </div></div><br>
Я опирался на код:<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838152'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T19:30:55+00:00">02.09.20, 19:30</time></span><div class='quote '>final var response = subject.submit(new Transfer.Request(<br>
    money,<br>
    () -&gt; sourceAccount,<br>
    () -&gt; destinationAccount,<br>
    () -&gt; { /* e.g. do nothing in this particular test case */ }<br>
));</div></div><br>
В данном тесте - последний параметр - это заглушка и, соответственно Request - это мок-объект.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838297</guid>
        <pubDate>Fri, 04 Sep 2020 15:18:21 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838297</link>
        <description><![CDATA[Grey goose: Некогда использовать такое. Надо баги фиксать  :lol:]]></description>
        <author>Grey goose</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838294</guid>
        <pubDate>Fri, 04 Sep 2020 15:09:29 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838294</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838292'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T14:43:44+00:00">04.09.20, 14:43</time></span><div class='quote '>Функция, которая ничего не делает - это заглушка, т.е. фактически это и есть mock. Каждый объект, в котором тебе нужна &quot;чистая функция&quot; - это есть твой mock-объект.</div></div><br>
Не совсем понял эту цитату. Ты точно понимаешь, что подразумевается под <a class='tag-url' href='https://ru.qwe.wiki/wiki/Pure_function' target='_blank'>чистыми функциями(Pure function)</a>?]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838292</guid>
        <pubDate>Fri, 04 Sep 2020 14:43:44 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838292</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838287'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:27:37+00:00">04.09.20, 13:27</time></span><div class='quote '>У меня-то их и нет.</div></div><br>
Ты пытаешься избавиться от них создавая левые параметры в Request&#39;е :)<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838287'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:27:37+00:00">04.09.20, 13:27</time></span><div class='quote '>Я не переписываю, я пытаюсь объяснить тебе, болезному, в чём разница между чистой функцией и объектом.</div></div><br>
Функция, которая ничего не делает - это заглушка, т.е. фактически это и есть mock. Каждый объект, в котором тебе нужна &quot;чистая функция&quot; - это есть твой mock-объект. <br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838287'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:27:37+00:00">04.09.20, 13:27</time></span><div class='quote '>Если они требуют разные входные данные, то, естественно у них будут разные типы аргумента. А ты что, клепаешь God object&#39;ы?</div></div><br>
Если у меня есть сущность &quot;пользователь&quot;, у которого есть фамилия, имя, день рождения, емыл и физический адрес (страна, город, индекс, улица, дом) и у меня есть 2 сервиса: 1) поздравляет пользователя с днем рождения по мылу и 2) отправляет новогоднюю открытку по почте, то я не буду шлепать 2 объекта так чтобы в одном были дата рождения и е-мыл, а в другом почтовый адрес. Я уж как-нибудь обойдуть одним объектом, который полностью описывает &quot;пользователя&quot; и не буду убиваться из-за некоторой избыточности. И нет, это не God object.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838287'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:27:37+00:00">04.09.20, 13:27</time></span><div class='quote '>В подавляющем большинстве случаев — да. Если функция не использует какие-то поля, то зачем эти поля нужны? Для красоты? </div></div><br>
В подавляющем случае как раз нет и в 99% случаев функция не использует все поля. Просто из-за того, что никто не будет шлепать отдельный объект ради каждой функции.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838287</guid>
        <pubDate>Fri, 04 Sep 2020 13:27:37 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838287</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Значит ли это, что других функций в классе Transfer нет?</div></div><br>
В моём — нет.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Или все другие функции должны точно также как и submit использовать все поля Request&#39;а?</div></div><br>
Ты чем читал? У каждой функции свои область определения и область значений. Что не ясно в этой фразе?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Я думал, что ты тут пытаешься избавиться от моков</div></div><br>
У меня-то их и нет.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Изменится то, что ты уже 2-й раз переписываешь свой код и все это ради того, чтобы не было моков.</div></div><br>
Я не переписываю, я пытаюсь объяснить тебе, болезному, в чём разница между чистой функцией и объектом.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Если в данном случае и можно вынести в статический метод (т.к. функция примитивна), то нельзя гаравтировать, что вынос в статику будет работать в любом случае.</div></div><br>
С чего б вдруг?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Или если у тебя 10 функций, то ты шлепаешь свой Request для каждой? </div></div><br>
Если они требуют разные входные данные, то, естественно у них будут разные типы аргумента. А ты что, клепаешь God object&#39;ы?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838286'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T13:04:46+00:00">04.09.20, 13:04</time></span><div class='quote '>Так чтобы каждая функция использовала все публичные поля своего Request&#39;а?</div></div><br>
В подавляющем большинстве случаев — да. Если функция не использует какие-то поля, то зачем эти поля нужны? Для красоты?]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838286</guid>
        <pubDate>Fri, 04 Sep 2020 13:04:46 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838286</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838285'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T12:16:11+00:00">04.09.20, 12:16</time></span><div class='quote '>Все используются, именно поэтому Request является типом аргумента submit. Это её (submit) область определения.</div></div><br>
Значит ли это, что других функций в классе Transfer нет? Или все другие функции должны точно также как и submit использовать все поля Request&#39;а?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838285'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T12:16:11+00:00">04.09.20, 12:16</time></span><div class='quote '>Ну тебе ж не нравилось, что я вызываю простую чистую функцию. Вот тебе альтернативное решение.</div></div><br>
Ты это для меня делаешь?  :lol: Я думал, что ты тут пытаешься избавиться от моков  :lol: <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838285'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T12:16:11+00:00">04.09.20, 12:16</time></span><div class='quote '>И что? Если они будут внешние, что принципиально изменится?</div></div><br>
Изменится то, что ты уже 2-й раз переписываешь свой код и все это ради того, чтобы не было моков. При этом код не становится понятнее. <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838285'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T12:16:11+00:00">04.09.20, 12:16</time></span><div class='quote '>Ну вынеси их в статику</div></div><br>
Если в данном случае и можно вынести в статический метод (т.к. функция примитивна), то нельзя гаравтировать, что вынос в статику будет работать в любом случае.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838285'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T12:16:11+00:00">04.09.20, 12:16</time></span><div class='quote '>Он говорит, что в классе не должно быть десяток каких-то функций, не имеющих отношения к классу. </div></div><br>
Ну значит у класса может быть больше одной функции. Слава богу&#33; Осталось только уточнить, могут ли эти функции использовать разные данные... Или если у тебя 10 функций, то ты шлепаешь свой Request для каждой? Так чтобы каждая функция использовала все публичные поля своего Request&#39;а?]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838285</guid>
        <pubDate>Fri, 04 Sep 2020 12:16:11 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838285</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Все знают публичные поля класса Request (имя и тип), но никто не знает какие из этих публичных полей используются функцией submit</div></div><br>
Все используются, именно поэтому Request является типом аргумента submit. Это её (submit) область определения.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>а, скажем, доступ к файловой системе нужно.</div></div><br>
Конечно, ведь это внешний ресурс с побочными эффектами.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Ты понимаешь, что вместо вызова некой функции (в данном случае canWithdraw) ты предлагаешь создать некое поле, которое должно заполняться гезультатом работы этой функции.</div></div><br>
Ну тебе ж не нравилось, что я вызываю простую чистую функцию. Вот тебе альтернативное решение.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>При этом мало того, что функцию все равно придется вызывать (в продуктивном коде)</div></div><br>
И что? Это дело этой функции, с точки зрения submit это просто bool.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>так еще у тебя и Request&#39;e добавится куча полей.</div></div><br>
Какая куча полей?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Смотри свой собственный код, у тебя у Account есть как минимум две функции: hasSameOwnerAs и canWithdraw</div></div><br>
И что? Если они будут внешние, что принципиально изменится?<br>
<br>
Ну вынеси их в статику<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">class Account {</div><div class="code_line">&nbsp;&nbsp; &nbsp;public final ID id;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public final Money balance;</div><div class="code_line">&nbsp;&nbsp; &nbsp;...</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static boolean haveSameOwners(Account a, Account b) { ... }</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static boolean canWithdraw(Account a, Money amount) { ... }</div><div class="code_line">}</div></ol></div></div></div></div><br>
Что-то поменялось?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Ясен хрен, что тут должна быть абстракция.</div></div><br>
:facepalm: с хера ли? Тебе что, инъекцию абстракций сделали?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Т.е. Request - это тоже нифига не plain data объект&#33;</div></div><br>
:facepalm: откуда такой глупый вывод?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>Это должен быть интерфейс типа</div></div><br>
Нет, не должен.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838284'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T11:40:00+00:00">04.09.20, 11:40</time></span><div class='quote '>ingle Responsibility Principle ничего не говорит о том, что в классе должна быть одна функция.</div></div><br>
Не говорит. Он говорит, что в классе не должно быть десяток каких-то функций, не имеющих отношения к классу.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838284</guid>
        <pubDate>Fri, 04 Sep 2020 11:40:00 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838284</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>В смысле «я знаю»? класс Request публичный с публичными полями. Все знают, как оно реализовано.</div></div><br>
Все знают публичные поля класса Request (имя и тип), но никто не знает какие из этих публичных полей используются функцией submit. А значит, для вызова submit тебе надо либо инициализировать все поля класса Request, либо знать какие поля класса Request использует submit, чтобы не создавать лишние объекты.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>может мне ещё и JDK мокать? java.lang.Math.sin, например?</div></div><br>
java.lang.Math.sin мокать не нужно, а, скажем, доступ к файловой системе нужно. <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>А то ж вдруг я его вызываю, да синус считаю. Ты сам-то мокаешь стандартную библиотеку?</div></div><br>
Я мокаю то, что мне нужно. Например доступ к реестр или доступ к файлам - тоже вполне себе стандартные штуки.<br>
 <br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>Также как и любое другое поле: передам нужное мне значение в конструктор</div></div><br>
Ты понимаешь, что вместо вызова некой функции (в данном случае canWithdraw) ты предлагаешь создать некое поле, которое должно заполняться гезультатом работы этой функции. При этом мало того, что функцию все равно придется вызывать (в продуктивном коде), так еще у тебя и Request&#39;e добавится куча полей.<br>
 <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>С хера ли? Ты что, Егора Бугаенко начитался/насмотрелся? Plain data там, никаких объектов, никаких абстракций.</div></div><br>
Не знаю кто такой Егор Бугаенко.<br>
Никаких plain data там нет. Смотри свой собственный код, у тебя у Account есть как минимум две функции: hasSameOwnerAs и canWithdraw плюс к этому read-only проперти owner. Ясен хрен, что тут должна быть абстракция.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>1) у каждой функции своя область определения, значит у каждой будет свой Request</div></div><br>
Отлично&#33; Т.е. Request - это тоже нифига не plain data объект&#33;<br>
Это должен быть интерфейс типа<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public interface IRequest</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; Money Amount {get;} // тут хз, возможно тоже должна быть абстракция</div><div class="code_line">&nbsp;&nbsp; IAccount Source {get;}</div><div class="code_line">&nbsp;&nbsp; IAccount Destination {get;}</div><div class="code_line">&nbsp;&nbsp; Action CheckCompliance{ get; set; }</div><div class="code_line">}</div></ol></div></div></div></div><br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>2) нафига перегружать модуль Transfer ещё десятком какимх-то функций? Про Single Responsibility Principle слышал?</div></div><br>
ingle Responsibility Principle ничего не говорит о том, что в классе должна быть одна функция.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838261</guid>
        <pubDate>Fri, 04 Sep 2020 06:18:58 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838261</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838259'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-04T05:13:10+00:00">04.09.20, 05:13</time></span><div class='quote '>Ортогональные. Но на ФП как-то код более декларативен получается по-умолчанию.</div></div>Ну не знаю. По моему все такое же описание процесса. Та же упомянутая тобой композиция функций отнюдь не декларативна.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838259</guid>
        <pubDate>Fri, 04 Sep 2020 05:13:10 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838259</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>Ты это знаешь только из-за того, что знаешь как оно реализовано.</div></div><br>
В смысле «я знаю»? класс Request публичный с публичными полями. Все знают, как оно реализовано.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>Затем, что ты этот метод вызываешь и действуешь исходя из возвращаемого этим методом значения.</div></div><br>
:facepalm: может мне ещё и JDK мокать? java.lang.Math.sin, например? А то ж вдруг я его вызываю, да синус считаю. Ты сам-то мокаешь стандартную библиотеку?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>Это поле надо будет как-то заполнить. Как ты собираешься это сделать?</div></div><br>
Также как и любое другое поле: передам нужное мне значение в конструктор. Ты сходи перечитай мой пример, там в самом конце показано. Или ты не знаешь, как структурки создавать? У тебя что, одни int&#39;ы и double&#39;ы в коде? Не пробовал там<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">struct Point {</div><div class="code_line">&nbsp;&nbsp; &nbsp;double x;</div><div class="code_line">&nbsp;&nbsp; &nbsp;double y;</div><div class="code_line">}</div></ol></div></div></div></div><br>
написать? Compound data type называется.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>(которые на секундочку должны быть полноценными объектами, а еще точнее абстракциями)</div></div><br>
С хера ли? Ты что, Егора Бугаенко начитался/насмотрелся? Plain data там, никаких объектов, никаких абстракций.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>Если у тебя в классе Transfer будет 10 функций (submit, rollback, list, rejeckt, еще что-то) и все они будут что-то рассчитывать опираять на данные из source и/или destination, то тебе придется добавлять 10 функций твой Request.</div></div><br>
:facepalm:<br>
1) у каждой функции своя область определения, значит у каждой будет свой Request<br>
2) нафига перегружать модуль Transfer ещё десятком какимх-то функций? Про Single Responsibility Principle слышал?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838228'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:22:09+00:00">03.09.20, 09:22</time></span><div class='quote '>А еще Account и Money чтобы работа шла так, как было задумано, а не по умолчанию</div></div><br>
:facepalm: Сходи int и (+) замокай, а то вдруг они как-то не так сработают и у тебя всё пойдёт не так как было задумано. И malloc заодно.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838235'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T12:34:11+00:00">03.09.20, 12:34</time></span><div class='quote '>ФП и декларативное программирование ортогональные вещи на самом деле.</div></div><br>
Ортогональные. Но на ФП как-то код более декларативен получается по-умолчанию.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838235</guid>
        <pubDate>Thu, 03 Sep 2020 12:34:11 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838235</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838225'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T09:03:55+00:00">03.09.20, 09:03</time></span><div class='quote '>Чушь. В мире ФП у тебя осталась история, что стул был непокрашенный, так же, как и в реальном.</div></div>Только в реальном мире это именно что история, объектами из которой ты не можешь воспользоваться, а в ФП вполне себе можешь :) ФП более высокая степень абстракции, чем императив, а значит дальше от реальности.<br>
Но мы отклонились от темы. ФП и декларативное программирование ортогональные вещи на самом деле.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838230</guid>
        <pubDate>Thu, 03 Sep 2020 09:53:43 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838230</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838204'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:56:55+00:00">03.09.20, 07:56</time></span><div class='quote '>Ну есть скажем требование: &quot;в случае неудачного соединения N-раз повторить повторить попытку, после чего сообщить пользователю об ощибке&quot;. Вполне себе нормальный сценарий, который тоже можно протестировать.</div></div><br>
GUI ты тоже юнит тестами тестишь? Вот есть скажем требование что размер формы должен быть 100x200, вполне себе нормальный сценарий, который тоже можно протестировать. Или скажем &quot;в случае неудачного соединения N-раз должно выскакивать окно - &quot;Подключение невозможно, проверьте параметры сети&quot;, которое должно располагаться по центру экрана&quot;. Вполне себе нормальный сценарий, который тоже можно протестировать. Ага?]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838228</guid>
        <pubDate>Thu, 03 Sep 2020 09:22:09 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838228</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Это pure data, там нечего мокать.</div></div><br>
Ты это знаешь только из-за того, что знаешь как оно реализовано.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Если ты про canWithdraw, то это простой чистый метод, зачем его мокать?</div></div><br>
Затем, что ты этот метод вызываешь и действуешь исходя из возвращаемого этим методом значения.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Но можно canWithdraw вынести в Request как Lazy&lt;Boolean&gt;-поле, и снова мокать ничего не надо.</div></div><br>
Это поле надо будет как-то заполнить. Как ты собираешься это сделать?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Я их сделал явными и ограниченными.</div></div><br>
Не сделал. Ты сделал 3 проперти (которые на секундочку должны быть полноценными объектами, а еще точнее абстракциями) и добавил указатель на функцию/делегат, которую надо вызвать в submit. Если у тебя в классе Transfer будет 10 функций (submit, rollback, list, rejeckt, еще что-то) и все они будут что-то рассчитывать опираять на данные из source и/или destination, то тебе придется добавлять 10 функций твой Request. А самое смешное, что если выносить эти функции в Request, то поля source, destination и money становятся не нужны :D<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Не надо, мне нужно знать только тип входных данных (Request) и тип выходных данных (Response), которые полностью описывают всё, что нужно.</div></div><br>
А еще Account и Money чтобы работа шла так, как было задумано, а не по умолчанию :)<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>вместо того, чтобы декомпозировать код и вынести логику retry в отдельный RetriableConnection с настраиваемой политикой, отдельно и независимо протестированную, Fester решил накостылять сомнительные тесты прям над бизнес-логикой, сохранив её сложность и зафиксировав эту сложность в спецификации (тесте).</div></div><br>
сорян конечно, но RetriableConnection тоже надо тестировать.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838225</guid>
        <pubDate>Thu, 03 Sep 2020 09:03:55 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838225</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>Ну в твоем синтетическом примере может и не полез бы, а в реальном декларативном коде не вознкает потребности в рефакторинге?<br>
</div></div><br>
Ну вот чуть менее синтетический:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">import Data.Function ((&amp;))</div><div class="code_line">import Text.Printf</div><div class="code_line">&nbsp;</div><div class="code_line">data SaleSum = SaleSum {</div><div class="code_line">&nbsp;&nbsp;totalCost &nbsp; &nbsp; :: Double,</div><div class="code_line">&nbsp;&nbsp;totalQuantity :: Int</div><div class="code_line">}</div><div class="code_line">&nbsp;</div><div class="code_line">class SaleSummary s where</div><div class="code_line">&nbsp;&nbsp;summary :: s -&#62; SaleSum</div><div class="code_line">&nbsp;</div><div class="code_line">instance Semigroup SaleSum where</div><div class="code_line">&nbsp;&nbsp;(SaleSum c1 q1) &#60;&#62; (SaleSum c2 q2) = SaleSum (c1 + c2) (q1 + q2)</div><div class="code_line">&nbsp;</div><div class="code_line">instance Monoid SaleSum where</div><div class="code_line">&nbsp;&nbsp;mempty = SaleSum 0.0 0</div><div class="code_line">&nbsp;</div><div class="code_line">instance Show SaleSum where</div><div class="code_line">&nbsp;&nbsp;show (SaleSum cost quantity) =</div><div class="code_line">&nbsp;&nbsp; &nbsp;&quot;Total cost = &quot; ++ printf &quot;%.2f&quot; cost ++ &quot;, quantity = &quot; ++ show quantity</div><div class="code_line">&nbsp;</div><div class="code_line">totalSummary :: SaleSummary s =&#62; [s] -&#62; SaleSum</div><div class="code_line">totalSummary xs = xs &amp; map summary &amp; mconcat</div><div class="code_line">&nbsp;</div><div class="code_line">----------------------------------------------------------------</div><div class="code_line">&nbsp;</div><div class="code_line">data Sale = Sale {</div><div class="code_line">&nbsp;&nbsp;itemID &nbsp; :: String,</div><div class="code_line">&nbsp;&nbsp;price &nbsp; &nbsp;:: Double,</div><div class="code_line">&nbsp;&nbsp;quantity :: Int</div><div class="code_line">&nbsp;&nbsp;-- maybe some other fields</div><div class="code_line">}</div><div class="code_line">&nbsp;</div><div class="code_line">instance SaleSummary Sale where</div><div class="code_line">&nbsp;&nbsp;summary s = SaleSum (price s * fromIntegral (quantity s)) (quantity s)</div><div class="code_line">&nbsp;</div><div class="code_line">testSales = [</div><div class="code_line">&nbsp;&nbsp;Sale &quot;Foo&quot; 0.20 4,</div><div class="code_line">&nbsp;&nbsp;Sale &quot;Bar&quot; 1.10 3</div><div class="code_line">&nbsp;&nbsp;]</div><div class="code_line">&nbsp;</div><div class="code_line">main = print $ totalSummary testSales</div></ol></div></div></div></div><br>
— <a class='tag-url' href='https://ideone.com/xcshAS' target='_blank'>https://ideone.com/xcshAS</a> <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-03T09:06:22+00:00">03.09.20, 09:06</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838219'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:51:18+00:00">03.09.20, 08:51</time></span><div class='quote '>в мире ФП у меня остался и покрашенный и непокрашенный</div></div><br>
Чушь. В мире ФП у тебя осталась история, что стул был непокрашенный, так же, как и в реальном.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838221</guid>
        <pubDate>Thu, 03 Sep 2020 08:55:07 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838221</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Программа и есть описание процесса, выполненное в той или иной нотации/модели.</div></div>Нет. Декларативная программа - это не описание процесса, это описание конечного результата.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838220</guid>
        <pubDate>Thu, 03 Sep 2020 08:54:22 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838220</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Чё-т не очень ему TDD помогает делать код/архитектуру лучше.</div></div><br>
Так не существует никаких волшебных техник, которые бы всегда приводили к тому, что любой человек начинает все правильно декомпозировать и архитектуру хорошую делать.<br>
Вопрос в том, помогает ли TDD в этом при прочих равных. Твой тезис в том, что не помогает, есть масса сторонников TDD, которые утверждают, что им помогает. И там и там в качестве аргументов - опыт.<br>
Со стороны судить сложно, так что я хочу попробовать это на своей практике и понять, насколько это помогает мне.<br>
<br>
Кстати, обе стороны могут оказаться правыми в том смысле, что если человек не обладал навыками декомпозиции и пр., а начитавшись про TDD и начав его применять, стал об этом задумываться, то естественно он получить улучшения, а потом будет считать, что именно TDD ему помог. Хотя дело может быть исключительно в том, что он в принципе стал задумываться о тех вещах, о которых раньше не думал.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838219</guid>
        <pubDate>Thu, 03 Sep 2020 08:51:18 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838219</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Что?</div></div>Декларативность не подразумевает вообще никакой последовательности действий. Ты объявил какой результат желаешь получить и условия его получения и опа все волшебно само-собой сложилось. Красота.<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>Не применима, т.к. позволяет менять уже существующие причинно-следственные события,</div></div>Каким образом императивная модель позволяет менять существующие события?<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838214'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:41:46+00:00">03.09.20, 08:41</time></span><div class='quote '>когда в реальном мире они не меняются, только порождаются новые. Чисто. Функционально.</div></div>Я не знаю в каком реальном мире ты живешь, но явно не в этой Вселенной. :D Допустим у меня есть стул и я его покрасил, в реальном мире у меня есть только покрашенный стул, в мире ФП у меня остался и покрашенный и непокрашенный. Чудеса в решете :) ФП переносит объекты из прошлого в настоящее. Машина времени прямо. :) <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-03T08:53:01+00:00">03.09.20, 08:53</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838215'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T08:44:51+00:00">03.09.20, 08:44</time></span><div class='quote '>Наличие дополнительного ручного тестирования никак не отменяет необходимость автоматических тестов на разных уровнях.<br>
А TDD - это вообще про написание кода больше </div></div>Ну да. Я не против автоматического тестирования вообще, я скорее разочарован в TDD, никак не помогает в конечном итоге, скорее мешает. Особенно если проект не очень крупный.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838215</guid>
        <pubDate>Thu, 03 Sep 2020 08:44:51 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838215</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838179'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:02:13+00:00">03.09.20, 07:02</time></span><div class='quote '>В жопу этот TDD, один хер реальное тестирование все равно происходит вручную в QA отделах.</div></div><br>
Да, давайте завалим QA отдел непротестированным говном, у них ведь мало работы на регрессе и проверке новой функциональности :lol: <br>
Наличие дополнительного ручного тестирования никак не отменяет необходимость автоматических тестов на разных уровнях.<br>
А TDD - это вообще про написание кода больше :) <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>но в подавляющем большинстве не критических для жизни людей проектов все именно так.</div></div><br>
Да, там еще, как правило, есть разные процедуры сертификации, а иногда и системы испытаний. Это никак не отменяет важность автоматического тестирования. Я бы даже сказал наоборот.<br>
Более того, когда такое ручное тестирование находит ошибку, то по возможности нужно добавить автоматические тесты на это. Люди в следующий раз могут пропустить эту ошибку или она может не воспроизвестись, например.<br>
Прогоны в CI позволят получить более надежную систему как раз :)]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838214</guid>
        <pubDate>Thu, 03 Sep 2020 08:41:46 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838214</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838202'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:53:07+00:00">03.09.20, 07:53</time></span><div class='quote '>Так и во втором варианте надо знать детали</div></div><br>
Какие?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838202'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:53:07+00:00">03.09.20, 07:53</time></span><div class='quote '>Как видишь Request придется тебе мокать целиком и полностью...</div></div><br>
Не вижу, зачем? Это pure data, там нечего мокать. Если ты про canWithdraw, то это простой чистый метод, зачем его мокать? Всякие БД и прочие внешние сервисы мокают из-за сайд-эффектов и из-за того, что поднимать БД/внешний сервис для каждого теста — крайне медленно.<br>
Но можно canWithdraw вынести в Request как Lazy&lt;Boolean&gt;-поле, и снова мокать ничего не надо.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838202'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:53:07+00:00">03.09.20, 07:53</time></span><div class='quote '>Как видим, ни от каких зависимостей ты не ушел</div></div><br>
Я их сделал явными и ограниченными.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838202'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:53:07+00:00">03.09.20, 07:53</time></span><div class='quote '>а реализацию тебе надо знать чтобы не мокать то, что не нужно в данном тесте.</div></div><br>
Не надо, мне нужно знать только тип входных данных (Request) и тип выходных данных (Response), которые полностью описывают всё, что нужно.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838203'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:55:12+00:00">03.09.20, 07:55</time></span><div class='quote '>Ага, пользуясь тем, что аргументы функции вычисляются гарантированно раньше самой функции.</div></div><br>
Что?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838203'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:55:12+00:00">03.09.20, 07:55</time></span><div class='quote '>Даже вон do-нотацию придумали, чтобы упростить маскировку.</div></div><br>
Нет, не для этого.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838203'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:55:12+00:00">03.09.20, 07:55</time></span><div class='quote '>Наш мир, в первую очередь, причинно-следственный, и поэтому императивная модель</div></div><br>
Не применима, т.к. позволяет менять уже существующие причинно-следственные события, когда в реальном мире они не меняются, только порождаются новые. Чисто. Функционально.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838203'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:55:12+00:00">03.09.20, 07:55</time></span><div class='quote '>Невозможно сварить борщ не составив последовательность действий. Даже если ты просто собираешь домик из готовых кубиков, ты не можешь начать строительство с крыши.</div></div><br>
Эти аналогии вообще к чему? По-твоему функциональные программы пишут на лету, в рантайме? Программа и есть описание процесса, выполненное в той или иной нотации/модели.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838204'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:56:55+00:00">03.09.20, 07:56</time></span><div class='quote '>Ну есть скажем требование: &quot;в случае неудачного соединения N-раз повторить повторить попытку, после чего сообщить пользователю об ощибке&quot;. Вполне себе нормальный сценарий, который тоже можно протестировать.</div></div><br>
Ну вот смотри, <strong class='tag-b'>D_KEY</strong>, вместо того, чтобы декомпозировать код и вынести логику retry в отдельный RetriableConnection с настраиваемой политикой, отдельно и независимо протестированную, Fester решил накостылять сомнительные тесты прям над бизнес-логикой, сохранив её сложность и зафиксировав эту сложность в спецификации (тесте). Чё-т не очень ему TDD помогает делать код/архитектуру лучше.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838204</guid>
        <pubDate>Thu, 03 Sep 2020 07:56:55 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838204</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838199'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:37:34+00:00">03.09.20, 07:37</time></span><div class='quote '>Зачем три попытки коннекта тестировать юнит тестами?</div></div><br>
Ну есть скажем требование: &quot;в случае неудачного соединения N-раз повторить повторить попытку, после чего сообщить пользователю об ощибке&quot;. Вполне себе нормальный сценарий, который тоже можно протестировать.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838203</guid>
        <pubDate>Thu, 03 Sep 2020 07:55:12 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838203</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838195'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:23:34+00:00">03.09.20, 07:23</time></span><div class='quote '>Никто ничего не маскирует, все пишут декларативную функциональную композицию. =)</div></div>Ага, пользуясь тем, что аргументы функции вычисляются <em class='tag-i'>гарантированно раньше</em> самой функции. Даже вон do-нотацию придумали, чтобы упростить маскировку.<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838195'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:23:34+00:00">03.09.20, 07:23</time></span><div class='quote '>Нет, наши физические компьютеры имеют императивную модель, а мир чисто конкурентно-событийный.</div></div>Наш мир, в первую очередь, причинно-следственный, и поэтому императивная модель куда ближе к этому миру, чем декларативная. Невозможно сварить борщ не составив последовательность действий. Даже если ты просто собираешь домик из готовых кубиков, ты не можешь начать строительство с крыши.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838202</guid>
        <pubDate>Thu, 03 Sep 2020 07:53:07 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838202</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838195'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:23:34+00:00">03.09.20, 07:23</time></span><div class='quote '>Вопрос в том, какого чёрта мы это как бы знаем, это деталь реализации, которую юнит-тест знать не должен.</div></div><br>
Так и во втором варианте надо знать детали :) Ну или можно не знать детали и мокать все, но тогда это будет, как ты сказал стаб :) <br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838195'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:23:34+00:00">03.09.20, 07:23</time></span><div class='quote '>Не надо мне мокать Request, я же написал пример теста, где там мок? </div></div><br>
Я не силен в Java, так что заранее прошу прощения, но:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;public Response submit(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;validate(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return transaction(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void validate(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkCompliance(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkBalance(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkCompliance(Request r) {</div><div class="code_line">// исходя из твоей логики, ты ничего не должен знать о реализации, а значит тебе придется мокать все проперти и методы как у source, так и у destination.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (r.source.val().hasSameOwnerAs(r.destination.val())) {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">// тут ты вызываешь заклушку, т.е. это таки Mock-объект от Request&#39;а</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;r.checkCompliance.val();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkBalance(Request r) {</div><div class="code_line">// canWithdraw - еще одна функция, которую ты забыл мокнуть в своем тесте :)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (r.source.val().canWithdraw(r.amount)) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">// надеюсь предусмотрен тест сценарий при котором будет вызывать это исключение... ну да, придется как-то иначе мокать canWithdraw, но что поделать?</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;throw new InsufficientFunds();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private Response transaction(Request r) {</div><div class="code_line">// ой, еще и Transaction надо мокнуть.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var transaction = Transaction.fresh(r.source.val().id, r.destination.val().id, r.amount);</div><div class="code_line">// а у source и destination еще и owner надо мокнуть, нет, зная реализацию Response мы понимаем, что null там вполне прокатит, но мы же исходим из того, что реализация нам не известна ;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new Response(</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;transaction,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new Response.Notification(r.source.val().owner, transaction.id, &quot;withdraw&quot;),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new Response.Notification(r.destination.val().owner, transaction.id, &quot;top up&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
Как видишь Request придется тебе мокать целиком и полностью... ну или делать из него стаб. Тут я не хочу обсуждать как правильно это все называть. Как видим, ни от каких зависимостей ты не ушел, а реализацию тебе надо знать чтобы не мокать то, что не нужно в данном тесте.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838199</guid>
        <pubDate>Thu, 03 Sep 2020 07:37:34 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838199</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838194'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:22:46+00:00">03.09.20, 07:22</time></span><div class='quote '>В данном случае это просто пример  В реальном мире это может быть не логгер, а, скажем, нужно совершить 3 попытки коннекта и потом кинуть исключение. Или убедиться, что какая-то функция была вызвана с опреденными параметрами.</div></div><br>
Зачем три попытки коннекта тестировать юнит тестами?  :blink: <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-03T07:39:15+00:00">03.09.20, 07:39</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838195'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:23:34+00:00">03.09.20, 07:23</time></span><div class='quote '>А это ещё одна проблема с моками: их любители часто думают, что пишут юнит-тест, но фактически получают интеграционный =)</div></div><br>
Ну вот как в примере выше Fester и пишет UT с моками, тестирует коннекты и логеры и называет это UT.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838195</guid>
        <pubDate>Thu, 03 Sep 2020 07:23:34 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838195</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838188'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:14:35+00:00">03.09.20, 07:14</time></span><div class='quote '>Не знаю как в Java, а NSubstitute умеет проверять какие методы, в каком порядке, сколько раз и с какими аргументами были вызваны. Вообще не вопрос.</div></div><br>
Да вопрос не в этом, как «технически» узнать. Mockito тоже всё это умеет. Вопрос в том, какого чёрта мы это как бы знаем, это деталь реализации, которую юнит-тест знать не должен.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838188'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:14:35+00:00">03.09.20, 07:14</time></span><div class='quote '>Никто не мешает тебе изменить контракт на</div></div><br>
Это никак не решает проблему: в интерфейсе Accounts десяток методов, метод submit использует только один из них. А может два, а может только при каких-то условиях. Об этом ничего не сказано в сигнатуре метода (входных параметрах), поэтому и юнит-тест этих деталей знать не должен. А значит, мокать нужно не отдельные вызовы метода Accounts.load, а <span class='tag-u'>все</span> методы Accounts, т.е. фактически делать не мок, а стаб. Либо в качестве зависимости нужно не Accounts указывать, а интерфейс, определённый в модуле Transfer и имеющий точно нужную сигнатуру, а ля<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">interface AccountLoader {</div><div class="code_line">&nbsp;&nbsp; &nbsp;Account load(Account.ID id);</div><div class="code_line">}</div></ol></div></div></div></div><br>
и его использовать в сигнатуре метода.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838188'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:14:35+00:00">03.09.20, 07:14</time></span><div class='quote '>Теперь тебе надо мокать Request и точно также мокать 2 аккаунта</div></div><br>
Не надо мне мокать Request, я же написал пример теста, где там мок? <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-03T07:24:57+00:00">03.09.20, 07:24</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838190'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:16:48+00:00">03.09.20, 07:16</time></span><div class='quote '>Это если речь идет о интеграционном тесте, он же пишет юнит тест.</div></div><br>
А это ещё одна проблема с моками: их любители часто думают, что пишут юнит-тест, но фактически получают интеграционный =) <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-03T07:29:44+00:00">03.09.20, 07:29</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838191'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:19:03+00:00">03.09.20, 07:19</time></span><div class='quote '>Да ни фига, просто маскируют императивность монадами да хвостовыми рекурсиями.</div></div><br>
Никто ничего не маскирует, все пишут декларативную функциональную композицию. =)<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838191'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:19:03+00:00">03.09.20, 07:19</time></span><div class='quote '> Так уж сложилось, что наш физический мир императивен</div></div><br>
Нет, наши физические компьютеры имеют императивную модель, а мир чисто конкурентно-событийный.<br>
Некоторые императивщики, конечно, пытаются переписать историю, но физически она не меняется.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838194</guid>
        <pubDate>Thu, 03 Sep 2020 07:22:46 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838194</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838186'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:12:17+00:00">03.09.20, 07:12</time></span><div class='quote '>Зачем это делать? Проверить правильно ли разработчики логгера его написали?</div></div><br>
В данном случае это просто пример :) В реальном мире это может быть не логгер, а, скажем, нужно совершить 3 попытки коннекта и потом кинуть исключение. Или убедиться, что какая-то функция была вызвана с опреденными параметрами.<br>
<br>
PS: у нас есть список строк по которому идет поиск ошибок в логах. Если изменяется выводимая в лог строка, то надо и этот список проапдейтить. Проверка контента в данном случае работает на ура. Правда должен признать, что это скорее прихоть шефа :D Он хочет когда-нибудь достичь дзена и вручить этот список клиентам, чтобы они сами научились локализовывать проблемы.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838191</guid>
        <pubDate>Thu, 03 Sep 2020 07:19:03 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838191</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838187'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:14:09+00:00">03.09.20, 07:14</time></span><div class='quote '>ФП достаточно декларативно.</div></div>Да ни фига, просто маскируют императивность монадами да хвостовыми рекурсиями. И в конечном счете все те же рефакторинги, тесты и косяки. Так уж сложилось, что наш физический мир императивен, поэтому копни любую декларативность и под ней будет архитолстенный слой махровой императивщины.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838190</guid>
        <pubDate>Thu, 03 Sep 2020 07:16:48 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838190</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838189'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:15:20+00:00">03.09.20, 07:15</time></span><div class='quote '>Интеграционный тест: правильно ли твой калькулятор пользуется логгером. =)</div></div><br>
Это если речь идет о интеграционном тесте, он же пишет юнит тест.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838189</guid>
        <pubDate>Thu, 03 Sep 2020 07:15:20 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838189</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838186'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:12:17+00:00">03.09.20, 07:12</time></span><div class='quote '>Зачем это делать?</div></div><br>
Интеграционный тест: правильно ли твой калькулятор пользуется логгером. =)]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838188</guid>
        <pubDate>Thu, 03 Sep 2020 07:14:35 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838188</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838152'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T19:30:55+00:00">02.09.20, 19:30</time></span><div class='quote '>– откуда мы знаем, что submit вообще вызовет accounts.load?<br>
– откуда мы знаем, что submit вызовет accounts.load с параметром sourceAccount.id?<br>
– откуда мы знаем, что submit не вызовет других методов accounts?</div></div><br>
Не знаю как в Java, а NSubstitute умеет проверять какие методы, в каком порядке, сколько раз и с какими аргументами были вызваны. Вообще не вопрос.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838152'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T19:30:55+00:00">02.09.20, 19:30</time></span><div class='quote '>Т.е. наличие параметра Accounts в публичном конструкторе — это часть контракта, публичная внешняя зависимость, а как именно используется экземпляр Accounts — это деталь реализации и «знание» этой детали в тесте — прямое нарушение инкапсуляции.</div></div><br>
Никто не мешает тебе изменить контракт на<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;public void submit(Accounts accounts, Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var source = accounts.load(r.source);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var destination = accounts.load(r.destination);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;validate(source, destination, r.amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var transaction = Transaction.fresh(r.source, r.destination, r.amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;transactions.store(transaction);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;notifyUsers(source, destination, transaction.id);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
:) Просто разработчику было лень пихать accounts в каждый вызов :)<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838152'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T19:30:55+00:00">02.09.20, 19:30</time></span><div class='quote '>Ни одной внешней зависимости с полным сохранением функциональности.</div></div><br>
Да брось&#33; Теже яйца, только в профиль :) Теперь тебе надо мокать Request и точно также мокать 2 аккаунта ;)]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838187</guid>
        <pubDate>Thu, 03 Sep 2020 07:14:09 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838187</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838184'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:11:30+00:00">03.09.20, 07:11</time></span><div class='quote '>Декларативное программирование красивое словечко не более того. Как коммунизм.</div></div><br>
ФП достаточно декларативно. Да даже в рамках традиционного ИП/ООП можно писать достаточно декларативно.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838186</guid>
        <pubDate>Thu, 03 Sep 2020 07:12:17 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838186</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>// тут же можно проверить, вызвался ли логгер с правильными данными<br>
   logger.Received(1).Info(&quot;Sum(2,2)&quot;);</div></div><br>
Зачем это делать? Проверить правильно ли разработчики логгера его написали? :huh:]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838185</guid>
        <pubDate>Thu, 03 Sep 2020 07:11:59 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838185</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838179'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:02:13+00:00">03.09.20, 07:02</time></span><div class='quote '>и все, валяются эти тесты годами и никогда не дают сбоев.</div></div><br>
Вот тоже с таким сталкивался.<br>
<br>
<strong class='tag-b'>D_KEY</strong>: во всяких этих стартапах зачастую рефакторинг и оптимизации проводят крайне редко, в основном, либо добавляют новые фичи, либо изменяют существующие, а это означает, что либо тесты правятся с каждым таким изменением, либо они валяются без реальной пользы, просто занимая лишнее время на билд проекта.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838184</guid>
        <pubDate>Thu, 03 Sep 2020 07:11:30 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838184</link>
        <description><![CDATA[applegame: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838180'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T07:06:47+00:00">03.09.20, 07:06</time></span><div class='quote '>«Важны тенденции, а не абсолютные показатели» — <s class='tag-s'>Отто Фон Бисмарк</s>D_KEY</div></div>Декларативное программирование красивое словечко не более того. Как коммунизм. Пишите декларативно:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#60;beautiful_life planet=&quot;earth&quot;/&#62;</div></ol></div></div></div></div><br>
Отличная программа я щетаю. Никаких рефакторингов, тестирования и прочего хлама. :lol: Осталось только написать The Browser, который сможет выполнить эту программу.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838183</guid>
        <pubDate>Thu, 03 Sep 2020 07:09:42 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838183</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>То, что логгинг интересен по ходу исполнения кода, а не &quot;на уровень выше&quot;.</div></div><br>
Логгинг интересен тогда, когда у тебя непонятный код, не покрытый UT, за который ты не ручаешься. Если у тебя все очевидно как работает - логирование нахрен и не нужно. Поэтому логгировать ты вполне себе можешь именно в том месте, где этому место, а не везде. Вот скажи, ты очевидные в реализации чистые функции, без сайд эффектов часто логируешь? И главное с какой целью?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>Вводится дополнительный класс с дополнительной логикой.</div></div><br>
Нет там класса с дополнительной логикой, там есть обертка инкапсулирующая в себе 2 класса.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>Сравни:</div></div><br>
И чем это лучше, расскажи пожалуйста? Плюс ко всему ты написал функцию с сайд эффектом. <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>И если в варианте с моком тестировать надо только одну функцию, то в предлагаемом тобой подходе тестировать надо 3 функции.</div></div><br>
Во втором варианте тестировать нужно тоже ровно 1 метод, без всяких моков. Неужели ты этого не понимаешь? Какой смысл тестировать например HttpClient/File/Logger/etc ?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>Просто в реальном мире данные надо брать из многих разных источноков, сопоставлать эти данные и принимать какое-либо решение.</div></div><br>
Так вот люди и изобретают всякие там паттерны, техники и практики, для того, чтобы делать гибкие, легко расширяемые, и тестируемые программы, а не хуяк хуяк и в продакшн, тут же целая философия существует написания эффективного кода.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838177'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T06:53:18+00:00">03.09.20, 06:53</time></span><div class='quote '>Именно для этого и нужны моки <br>
В примере выше тест для суммы выглядел бы так:</div></div><br>
Ага, только вот тебе автор как раз и пишет - что эти самые моки являются жесткой зависимостью, ты не можешь протестировать эту функцию без мока, в итоге мы приходим к тому, что тесты зачастую сложнее, чем само приложение, в итоге польза от таких UT стремится к нулю, а все тестирование сводится к тестированию моков. Ты статью то почитай, а :D]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838180</guid>
        <pubDate>Thu, 03 Sep 2020 07:06:47 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838180</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838157'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T21:16:06+00:00">02.09.20, 21:16</time></span><div class='quote '>По крайней мере не раньше, чем меритократические тенденции возобладают в РФ</div></div><br>
Ну ладно, возвращаю тебе избирательное право =)<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838170'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>applegame &#064; <time class="tag-quote__quoted-time" datetime="2020-09-03T04:21:42+00:00">03.09.20, 04:21</time></span><div class='quote '>По мне так декларативный код - утопия.</div></div><br>
«Важны тенденции, а не абсолютные показатели» — <s class='tag-s'>Отто Фон Бисмарк</s>D_KEY<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838157'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T21:16:06+00:00">02.09.20, 21:16</time></span><div class='quote '>Ну, скажем, у тебя из-за (слишком) ленивых вычислений в программе на haskell появляются моменты, когда память то почти свободна, то лавинообразно забивается и все начинает тупить.<br>
Соответственно, можно чуть иначе попытаться написать код и расход память станет стабильнее.</div></div><br>
Для этого нужно минимум изменений, которые никак не меняют логику.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838179</guid>
        <pubDate>Thu, 03 Sep 2020 07:02:13 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838179</link>
        <description><![CDATA[applegame: В жопу этот TDD, один хер реальное тестирование все равно происходит вручную в QA отделах. Есть конечно исключения, но в подавляющем большинстве не критических для жизни людей проектов все именно так.<br>Лично я пишу иногда тесты, но они как правило одноразовые. То есть потестировал, ошибки нашел, исправил, и все, валяются эти тесты годами и никогда не дают сбоев.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838177</guid>
        <pubDate>Thu, 03 Sep 2020 06:53:18 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838177</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838133'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:25:13+00:00">02.09.20, 15:25</time></span><div class='quote '>Так и что с ним не так то?</div></div><br>
То, что логгинг интересен по ходу исполнения кода, а не &quot;на уровень выше&quot;.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838133'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:25:13+00:00">02.09.20, 15:25</time></span><div class='quote '>С чего вдруг сложной? В чем заключается сложность? Я не понимаю.</div></div><br>
Вводится дополнительный класс с дополнительной логикой.<br>
Сравни:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;interface ILogger</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;void Info (string message);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;interface ICalculator</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;int Sum(int a, int b);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp;public class Calculator : ICalculator</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; ILogger _logger = null;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public Calculator (ILogger logger)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_logger = logger;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public int Sum(int a, int b)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_logger?.Info ($&quot;Sum({a},{b})&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return a + b;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
и<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp; &nbsp;interface ILogger</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;void Info (string message);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;interface ICalculatorWithIO</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;int Sum(int a, int b);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;interface ICalculator : ICalculatorWithIO</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public class Calculator : ICalculator</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public int Sum(int a, int b)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return a + b;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public class CalculatorWithLogger : ICalculatorWithIO</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; private ICalculator _calculator;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; private readonly ILogger _logger;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public CalculatorWithLogger(ICalculator calc, ILogger logger)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (calc == null)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new ArgumentNullException (&quot;Calculator must be initialized.&quot;);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _calculator = calc;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _logger = logger;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; public int Sum(int a, int b)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_logger?.Info ($&quot;Call method Sum({a},{b})&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return _calculator.Sum(a, b);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div></ol></div></div></div></div><br>
<br>
И если в варианте с моком тестировать надо только одну функцию, то в предлагаемом тобой подходе тестировать надо 3 функции.<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838133'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:25:13+00:00">02.09.20, 15:25</time></span><div class='quote '>Если у тебя функция и жнец и жрец и на дуде игрец, тогда это явно говорит о плохом дизайне в твоем приложении и о жестких зависимостях, от которых нужно избавляться.</div></div><br>
Просто в реальном мире данные надо брать из многих разных источноков, сопоставлать эти данные и принимать какое-либо решение.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838133'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:25:13+00:00">02.09.20, 15:25</time></span><div class='quote '>Тестируемая функция в ЮТ не должна не от чего зависеть, она должна быть автономной. Т.е. если у тебя в каком то 1 методе ошибка. То в юнит тестах - должен быть сфейлен ровно 1 UT из 1000 запущенных, даже если в программе у тебя куча мест, которые используют эту функцию/метод.</div></div><br>
Именно для этого и нужны моки :)<br>
В примере выше тест для суммы выглядел бы так:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public void Sum_2plus2_4 ()</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; // Arrange</div><div class="code_line">&nbsp;&nbsp; ILogger logger = Substitute.For&#60;ILogger&#62;();</div><div class="code_line">&nbsp;&nbsp; ICalculator calc = new Calculator (logger);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; // Act</div><div class="code_line">&nbsp;&nbsp; int res = calc.Sum (2, 2);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; // Assert</div><div class="code_line">&nbsp;&nbsp; Assert::AreEqual (4, res);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; // тут же можно проверить, вызвался ли логгер с правильными данными</div><div class="code_line">&nbsp;&nbsp; logger.Received(1).Info(&quot;Sum(2,2)&quot;);</div><div class="code_line">}</div></ol></div></div></div></div><br>
как видишь, тут совершенно наплевать сколько там ошибок в логгере. Этот тест от кода логгера не зависит.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838170</guid>
        <pubDate>Thu, 03 Sep 2020 04:21:42 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838170</link>
        <description><![CDATA[applegame: По мне так декларативный код - утопия.]]></description>
        <author>applegame</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838157</guid>
        <pubDate>Wed, 02 Sep 2020 21:16:06 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838157</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838152'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T19:30:55+00:00">02.09.20, 19:30</time></span><div class='quote '>Так я ж бомблю, что его почти не пишут, этот самый декларативный код, предпочитая обмазаться тестами и говнякать =)</div></div><br>
Так и не начнут же :) <br>
По крайней мере не раньше, чем меритократические тенденции возобладают в РФ :lol: <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>А хорошо получалось или было все нестабильно?</div></div><br>
Всё было плохо.<br>
</div></div><br>
Ну значит или те, кто нахваливают TDD врут, или у тех, кого ты видил, было что-то не так сделано. Ну и вообще основная проблема-то может быть вообще в кадрах :D <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Если у тебя новые требование (новая формула, скажем, умножать нужно не на два, а на три), то естественно нужно написать новую функцию и использовать там, где нужно, а не трогать старую. Ты что, open-close принцип забыл?</div></div><br>
Я просто не могу смапить твой синтетический пример на реальный код :) <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><br>
А что такое «оптимизация декларативного кода»? <br>
</div></div><br>
Ну, скажем, у тебя из-за (слишком) ленивых вычислений в программе на haskell появляются моменты, когда память то почти свободна, то лавинообразно забивается и все начинает тупить.<br>
Соответственно, можно чуть иначе попытаться написать код и расход память станет стабильнее.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838152</guid>
        <pubDate>Wed, 02 Sep 2020 19:30:55 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838152</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>а в реальном декларативном коде не вознкает потребности в рефакторинге?</div></div><br>
Так я ж бомблю, что его почти не пишут, этот самый декларативный код, предпочитая обмазаться тестами и говнякать =) <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T19:36:10+00:00">02.09.20, 19:36</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>А хорошо получалось или было все нестабильно?</div></div><br>
Всё было плохо.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>А, то есть мы полностью переписываем код каждый раз?</div></div><br>
Зачем каждый раз? Если ты про то, чтобы переиспользовать эту функцию в новой фиче, то если она подходит, можно и переиспользовать, но тогда две фичи будут от неё зависеть и менять её нельзя. Да и зачем? Если у тебя новые требование (новая формула, скажем, умножать нужно не на два, а на три), то естественно нужно написать новую функцию и использовать там, где нужно, а не трогать старую. Ты что, open-close принцип забыл?<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>То, что если он недекларативен ради оптимизации, то тогда тесты имеет смысл писать?</div></div><br>
Ну да, если это нечитаемое байтоковыряние, конечно, надо.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838131'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:13:32+00:00">02.09.20, 15:13</time></span><div class='quote '>А что, декларативный код не оптимизируют?</div></div><br>
А что такое «оптимизация декларативного кода»? <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T19:59:15+00:00">02.09.20, 19:59</time></span></span><br>
К слову о моках и в чём с ними проблема.<br>
<br>
Допустим, есть у нас такой сервис:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public final class Transfer {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static final class Request {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Account.ID source;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Account.ID destination;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Money amount;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public Request(Account.ID source, Account.ID destination, Money amount) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.source = source;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.destination = destination;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.amount = amount;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static final class InsufficientFunds extends RuntimeException {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private final Accounts accounts;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private final Compliance compliance;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private final Transactions transactions;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private final Notifier notifier;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public Transfer(Accounts accounts, Compliance compliance, Transactions transactions, Notifier notifier) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;this.accounts = accounts;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;this.compliance = compliance;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;this.transactions = transactions;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;this.notifier = notifier;</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public void submit(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var source = accounts.load(r.source);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var destination = accounts.load(r.destination);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;validate(source, destination, r.amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var transaction = Transaction.fresh(r.source, r.destination, r.amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;transactions.store(transaction);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;notifyUsers(source, destination, transaction.id);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void validate(Account source, Account destination, Money amount) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkCompliance(source, destination, amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkBalance(source, amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkCompliance(Account source, Account destination, Money amount) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (source.hasSameOwnerAs(destination)) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;compliance.validateTransfer(source.owner, destination.owner, amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkBalance(Account source, Money amount) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (source.canWithdraw(amount)) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;throw new InsufficientFunds();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void notifyUsers(Account source, Account destination, Transaction.ID transaction) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;notifier.notify(source.owner, transaction, &quot;withdraw&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;notifier.notify(destination.owner, transaction, &quot;top up&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
<br>
у него четыре внешние зависимости, вот одна из них:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public interface Accounts {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Account load(Account.ID id);</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// more methods</div><div class="code_line">&nbsp;&nbsp; &nbsp;// ...</div><div class="code_line">}</div></ol></div></div></div></div><br>
три другие примерно такие же: интерфейсы с разными методами, я описал только те, что используются в сервисе Transfer.<br>
<br>
теперь для юнит-тестов мы мокаем эти интерфейсы, как обычно это делают, что-то вроде<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">final var accounts = Mockito.mock(Accounts);</div><div class="code_line">...</div><div class="code_line">final var sourceAccount = // new account</div><div class="code_line">...</div><div class="code_line">when(accounts.load(sourceAccount.id)).thenReturn(sourceAccount);</div><div class="code_line">...</div><div class="code_line">subject.submit(new Transfer.Request(sourceAccount.id, ...));</div><div class="code_line">...</div><div class="code_line">// assertions on mocked Transactions DB and Notifier?</div></ol></div></div></div></div><br>
и тут возникают вопросы:<br>
– откуда мы знаем, что submit вообще вызовет accounts.load?<br>
– откуда мы знаем, что submit вызовет accounts.load с параметром sourceAccount.id?<br>
– откуда мы знаем, что submit не вызовет других методов accounts?<br>
Этого нет в публичном интерфейсе (здесь я имею ввиду публичные методы и конструкторы) класса Transfer, нет в его «контракте». Фактически это — деталь реализации.<br>
<br>
Т.е. наличие параметра Accounts в публичном конструкторе — это часть контракта, публичная внешняя зависимость, а как именно используется экземпляр Accounts — это деталь реализации и «знание» этой детали в тесте — прямое нарушение инкапсуляции.<br>
<br>
Теперь рассмотрим альтернативу:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public final class Transfer {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static final class Request {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Money amount;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Lazy&#60;Account&#62; source;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Lazy&#60;Account&#62; destination;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Lazy&#60;Void&#62; checkCompliance;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public Request(Money amount, Lazy&#60;Account&#62; source, Lazy&#60;Account&#62; destination, Lazy&#60;Void&#62; checkCompliance) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.amount = amount;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.source = source;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.destination = destination;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.checkCompliance = checkCompliance;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static final class Response {</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Transaction transaction;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public final Notification[] notifications;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;private Response(Transaction transaction, Notification... notifications) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.transaction = transaction;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.notifications = notifications;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;public static final class Notification {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public final User.ID user;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public final Transaction.ID transaction;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public final String message;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public Notification(User.ID user, Transaction.ID transaction, String message) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.user = user;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.transaction = transaction;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;this.message = message;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public static final class InsufficientFunds extends RuntimeException {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;public Response submit(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;validate(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return transaction(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void validate(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkCompliance(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;checkBalance(r);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkCompliance(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (r.source.val().hasSameOwnerAs(r.destination.val())) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;r.checkCompliance.val();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private void checkBalance(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (r.source.val().canWithdraw(r.amount)) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;throw new InsufficientFunds();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;private Response transaction(Request r) {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;final var transaction = Transaction.fresh(r.source.val().id, r.destination.val().id, r.amount);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new Response(</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;transaction,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new Response.Notification(r.source.val().owner, transaction.id, &quot;withdraw&quot;),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;new Response.Notification(r.destination.val().owner, transaction.id, &quot;top up&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">}</div></ol></div></div></div></div><br>
Ни одной внешней зависимости с полным сохранением функциональности.<br>
<br>
Примерный тест:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">final var sourceAccount = // new account</div><div class="code_line">...</div><div class="code_line">final var response = subject.submit(new Transfer.Request(</div><div class="code_line">&nbsp;&nbsp; &nbsp;money,</div><div class="code_line">&nbsp;&nbsp; &nbsp;() -&#62; sourceAccount,</div><div class="code_line">&nbsp;&nbsp; &nbsp;() -&#62; destinationAccount,</div><div class="code_line">&nbsp;&nbsp; &nbsp;() -&#62; { /* e.g. do nothing in this particular test case */ }</div><div class="code_line">));</div><div class="code_line">&nbsp;</div><div class="code_line">// assertions on response</div></ol></div></div></div></div><br>
И никаких моков нафиг не надо.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838133</guid>
        <pubDate>Wed, 02 Sep 2020 15:25:13 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838133</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838132'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:16:03+00:00">02.09.20, 15:16</time></span><div class='quote '>Логгинг в этом плане идеальный пример, т.к. логгером можно отслеживать процесс. Согласись, далеко не все функии умещаются в одну строку. И логгинг бывает разного уровня (debug, info, warn, error, fatal итд).</div></div><br>
Так и что с ним не так то? :-? <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838132'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:16:03+00:00">02.09.20, 15:16</time></span><div class='quote '>Прикол в том, что 3-й класс делает систему неоправданно сложной.</div></div><br>
С чего вдруг сложной? В чем заключается сложность? Я не понимаю.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838132'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:16:03+00:00">02.09.20, 15:16</time></span><div class='quote '>Весь прикол заключает в том, что <strong class='tag-b'>если пользоваться терминологией автора этой статьи (т.е. UT не имеет мок-объектов, а то, что имеет мок-объекты - это интергационные тесты)</strong>, то не существует систем, которые тестируются юнит-тестами </div></div><br>
Ни автор, ни я не писали того, что выделенно жирным в твоей цитате.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838132'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:16:03+00:00">02.09.20, 15:16</time></span><div class='quote '>Юнит-тестами можно протестировать только базовые компоненты, а продуктивный (aka полезный) код тестируется исключительно интеграционными тестами.</div></div><br>
Если у тебя функция и жнец и жрец и на дуде игрец, тогда это явно говорит о плохом дизайне в твоем приложении и о жестких зависимостях, от которых нужно избавляться.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838132'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:16:03+00:00">02.09.20, 15:16</time></span><div class='quote '>Например, у нас есть модуль, который контролирует передачу RFID чипов. Каждый евент от RFID-антенны сохраняется в БД и передается от 0 до n раз на 5 других подсистем. И вся информация о правильном поведении идет из вне  Ну и каких &quot;юнит-тестах&quot; (в понимании автора статьи) тут можно говорить?</div></div><br>
Юнит тестами тестируют конкретные функции/методы, ты же привел какой то юзер кейс, который должен тестироваться интеграционными тестами.<br>
Тестируемая функция в ЮТ не должна не от чего зависеть, она должна быть автономной. Т.е. если у тебя в каком то 1 методе ошибка. То в юнит тестах - должен быть сфейлен ровно 1 UT из 1000 запущенных, даже если в программе у тебя куча мест, которые используют эту функцию/метод.<br>
Если же у тебя сфейлилось 50 юнит тестов, из за того, что в ровно 1 методе у тебя ошибка, значит с твоими юнит тестами что то не то, и их ценность стремится к нулю.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838132</guid>
        <pubDate>Wed, 02 Sep 2020 15:16:03 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838132</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838122'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:26:19+00:00">02.09.20, 12:26</time></span><div class='quote '>Но у тебя в ТЗ оговорено что класс должен и логировать и вычислять сумму.</div></div><br>
Логгинг в этом плане идеальный пример, т.к. логгером можно отслеживать процесс. Согласись, далеко не все функии умещаются в одну строку. И логгинг бывает разного уровня (debug, info, warn, error, fatal итд).<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838122'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:26:19+00:00">02.09.20, 12:26</time></span><div class='quote '>Соответственно первый класс для вычисления суммы, второй для логирования, а третий агрегирует в себе эти два.</div></div><br>
Прикол в том, что 3-й класс делает систему неоправданно сложной. <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838122'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:26:19+00:00">02.09.20, 12:26</time></span><div class='quote '>Вот автор и описывает - что такой подход ведет к запутанности, сильной зависимости, и соответственно к подводным камням и ошибкам.</div></div><br>
Весь прикол заключает в том, что если пользоваться терминологией автора этой статьи (т.е. UT не имеет мок-объектов, а то, что имеет мок-объекты - это интергационные тесты), то не существует систем, которые тестируются юнит-тестами :) Юнит-тестами можно протестировать только базовые компоненты, а продуктивный (aka полезный) код тестируется исключительно интеграционными тестами.<br>
Например, у нас есть модуль, который контролирует передачу RFID чипов. Каждый евент от RFID-антенны сохраняется в БД и передается от 0 до n раз на 5 других подсистем. И вся информация о правильном поведении идет из вне :) Ну и каких &quot;юнит-тестах&quot; (в понимании автора статьи) тут можно говорить?]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838131</guid>
        <pubDate>Wed, 02 Sep 2020 15:13:32 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838131</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838130'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T15:01:57+00:00">02.09.20, 15:01</time></span><div class='quote '>Зачем ты начал рефакторить то, что и так ясно отражает суть?<br>
Про оптимизацию я уже писал, но ты всё пропустил.</div></div><br>
Ну в твоем синтетическом примере может и не полез бы, а в реальном декларативном коде не вознкает потребности в рефакторинге?<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Видел я как такой стартап использует эти практики. Ничем от херак-херак не отличается.</div></div><br>
А хорошо получалось или было все нестабильно?<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Э нет, делать фичу — это новые требования и новая реализация.</div></div><br>
А, то есть мы полностью переписываем код каждый раз? :D <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Про оптимизации я уже писал.<br>
</div></div><br>
То, что если он недекларативен ради оптимизации, то тогда тесты имеет смысл писать?<br>
А что, декларативный код не оптимизируют?]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838130</guid>
        <pubDate>Wed, 02 Sep 2020 15:01:57 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838130</link>
        <description><![CDATA[korvin: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838106'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T08:46:59+00:00">02.09.20, 08:46</time></span><div class='quote '>Простой пример. Начал рефакторить или оптимизировать, ошибся в чем-то. Сломал.</div></div><br>
Зачем ты начал рефакторить то, что и так ясно отражает суть?<br>
Про оптимизацию я уже писал, но ты всё пропустил.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838106'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T08:46:59+00:00">02.09.20, 08:46</time></span><div class='quote '>Как раз обычно все эти быстрые стартапы часто активно используют эти &quot;новые&quot; хорошие инженерные практики</div></div><br>
Видел я как такой стартап использует эти практики. Ничем от херак-херак не отличается.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838106'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T08:46:59+00:00">02.09.20, 08:46</time></span><div class='quote '>Программисты такие, знаешь ли. Код правят. Делали фичу, рефакторили, оптимизировали - выбирай на свой вкус.</div></div><br>
Э нет, делать фичу — это новые требования и новая реализация. Рефакторят говнокод, а этот код чист, декларативен и понятен, идеален, его не нужно рефакторить =)<br>
Про оптимизации я уже писал.<br>
Кроме того, во многих сервисных проектах (особенно в этих ваших стартапах) проблемы производительности возникают обычно не в коде и не с первых годов жизни проекта.]]></description>
        <author>korvin</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838124</guid>
        <pubDate>Wed, 02 Sep 2020 13:19:53 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838124</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838123'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:44:58+00:00">02.09.20, 12:44</time></span><div class='quote '>Я может плаваю в теории, но в интеграционных тестах вместо моков уже должны быть реальные объекты, разве нет?</div></div><br>
Ну вот автор пишет что нет. Плюс есть мнение, и это не только у этого автора я читал, что в интеграционных тестах - моками имитируются все ситуации, которые могут быть. Реальный объект, не реальный объект, серверная атака, имитация ошибки, имитация с отключенным соединением и т.д. и т.п. <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838123'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:44:58+00:00">02.09.20, 12:44</time></span><div class='quote '>А так все верно, да. Просто я бы предложил перед интеграционными тестами, делать еще ЮТ с моками, чтобы некоторые ошибки отлавливать раньше запуска интеграционных тестов.</div></div><br>
Ну вот а автор пишет, что такой подход лишен смысла напрочь. Потому что твой код с тестами разрастается, и в итоге ничего не покрывает и толку от них 0, типа все сведется к тому, что ты будешь моки тестировать, а не свой функционал.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838123'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T12:44:58+00:00">02.09.20, 12:44</time></span><div class='quote '>Вот если вместо &quot;говорит о том, что модули сильно взаимосвязаны&quot; написать &quot;может говорить о том, что модули сильно взаимосвязаны&quot;, то я соглашусь </div></div><br>
Выдрал специально для тебя:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><br>
What is a code smell?<br>
“A code smell is a surface indication that usually corresponds to a deeper problem in the system.” ~ Martin Fowler<br>
A code smell does not mean that something is definitely wrong, or that something must be fixed right away. It is a rule of thumb that should alert you to a possible opportunity to improve something.<br>
This text and its title in no way imply that all mocking is bad, or that you should never mock anything.<br>
Additionally, different types of code need different levels (and different kinds) of mocks. Some code exists primarily to facilitate I/O, in which case, there is little to do other than test I/O, and reducing mocks might mean your unit test coverage would be close to 0.<br>
If there is no logic in your code (just pipes and pure compositions), 0% unit test coverage might be acceptable, assuming your integration or functional test coverage is close to 100%. However, if there is logic (conditional expressions, assignments to variables, explicit function calls to units, etc…), you probably do need unit test coverage, and there may be opportunities to simplify your code and reduce mocking requirements.<br>
---<br>
What is tight coupling?<br>
The need to mock in order to achieve unit isolation for the purpose of unit tests is caused by coupling between units. Tight coupling makes code more rigid and brittle: more likely to break when changes are required. In general, less coupling is desirable for its own sake because it makes code easier to extend and maintain. The fact that it also makes testing easier by eliminating the need for mocks is just icing on the cake.<br>
From this we can deduce that if we’re mocking something, there may be an opportunity to make our code more flexible by reducing the coupling between units. Once that’s done, you won’t need the mocks anymore.<br>
Coupling is the degree to which a unit of code (module, function, class, etc…) depends upon other units of code. Tight coupling, or a high degree of coupling, refers to how likely a unit is to break when changes are made to its dependencies. In other words, the tighter the coupling, the harder it is to maintain or extend the application. Loose coupling reduces the complexity of fixing bugs and adapting the application to new use-cases.<br>
---<br>
What does composition have to do with mocking?<br>
Everything. The essence of all software development is the process of breaking a large problem down into smaller, independent pieces (decomposition) and composing the solutions together to form an application that solves the large problem (composition).<br>
Mocking is required when our decomposition strategy has failed.<br>
Mocking is required when the units used to break the large problem down into smaller parts depend on each other. Put another way, mocking is required when our supposed atomic units of composition are not really atomic, and our decomposition strategy has failed to decompose the larger problem into smaller, independent problems.<br>
When decomposition succeeds, it’s possible to use a generic composition utility to compose the pieces back together. Examples:<br>
---<br>
When you use generic composition utilities, each element of the composition can be unit tested in isolation without mocking the others.<br>
The compositions themselves will be declarative, so they’ll contain zero unit-testable logic (presumably the composition utility is a third party library with its own unit tests).<br>
Under those circumstances, there’s nothing meaningful to unit test. You need integration tests, instead.<br>
</div></div>]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838123</guid>
        <pubDate>Wed, 02 Sep 2020 12:44:58 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838123</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Если мы пишем так как в статье, значит нам уже не надо писать дополнительно ЮТ. Мы с них начинаем писать. Пишем тест, потом функционал. А уж потом дополнительно пишем интеграционные тесты, где с помощью моков эмулируем различные сценарии.</div></div><br>
Я может плаваю в теории, но в интеграционных тестах вместо моков уже должны быть реальные объекты, разве нет?<br>
А так все верно, да. Просто я бы предложил перед интеграционными тестами, делать еще ЮТ с моками, чтобы некоторые ошибки отлавливать раньше запуска интеграционных тестов.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Ну и автор не говорит что нельзя моки юзать в ЮТ и все тут, он как бы намекает, что если в ЮТ используются Моки то это уже говорит о том, что модули сильно взаимосвязаны, и можно переписать куда лучше, чтоб избавится от моков.</div></div><br>
Вот если вместо &quot;говорит о том, что модули сильно взаимосвязаны&quot; написать &quot;<strong class='tag-b'>может</strong> говорить о том, что модули сильно взаимосвязаны&quot;, то я соглашусь :)]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838122</guid>
        <pubDate>Wed, 02 Sep 2020 12:26:19 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838122</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838121'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T11:31:54+00:00">02.09.20, 11:31</time></span><div class='quote '>Принцип единственной ответственности не запрещает DI и не запрещает общаться с другими компонентами.</div></div><br>
Конечно. Но у тебя в ТЗ оговорено что класс должен и логировать и вычислять сумму. Соответственно первый класс для вычисления суммы, второй для логирования, а третий агрегирует в себе эти два.<br>
В чем конкретно проблема то? Как ты напишешь эту задачу? И в чем будет профит от твоего решения, я не пойму?<br>
Ты хочешь ввести в свой метод внешние зависимости и потом тестировать это с помощью UT?<br>
В итоге ты получаешь более зависимый тест, который может грохнуться из за того же логера, получаешь дополнительную кладезь ошибок, тебе придется передавать этот логер в ЮТ. Т.е. у тебя функция вычисляет сумму двух чисел, и помимо этого делает еще что то, что делать не должна.<br>
Вот автор и описывает - что такой подход ведет к запутанности, сильной зависимости, и соответственно к подводным камням и ошибкам.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838121'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T11:31:54+00:00">02.09.20, 11:31</time></span><div class='quote '>Ну т.е. все сводится к тому какой тест можно назвать юнит-тестом, а какой уже интеграционный. Вопрос не в сути, а в терминологии. При этом ради сохранения чистоты терминологии автор готов пойти на усложнение кода и, соответственно, добавление ошибок.</div></div><br>
Нет, ты все не так понял. Я тебе советую перечитать статью, на всякий случай продублирую ее еще раз: <a class='tag-url' href='https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a' target='_blank'>https://medium.com/javascript-scene/mocking...ll-944a70c90a6a</a><br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838121'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T11:31:54+00:00">02.09.20, 11:31</time></span><div class='quote '>И не просто так придется вводить интерфейс. Т.к. у тебя будет<br>
Calculator : ICalculator<br>
CalculatorWithLogger : ICalculator<br>
CalculatorWithDatabase : ICalculator<br>
CalculatorWithLoggarAndDatabase : ICalculator<br>
что, как ты понимаешь, легко может привести к ошибке.<br>
<br>
Для исключения ошибки тебе придется вводить еще один интерфейс:<br>
Calculator : ICalculatorUnit<br>
CalculatorWithLogger : ICalculator<br>
CalculatorWithDatabase : ICalculator<br>
CalculatorWithLoggarAndDatabase : ICalculator</div></div><br>
Ты не понял о каком интерфейсе я говорил.<br>
<br>
ICalculator - это интерфейс для реализации калькуляторов, зачем его вообще трогать?<br>
<br>
У тебя будет интерфейс, который призван объединить вычисление с IO, какой нить:<br>
ICalculatorWithIO или что то подобное. Не суть важно.<br>
В принципе, вместо интерфейса ICalculator, можно взять абстрактный класс например и наследовать свои калькуляторы от него, если тебя смущает именно интерфейс, но можно и интерфейс, просто этот интерфейс(ICalculator) будет внутренним, если можно так выразиться. А ICalculatorWithIO - внешним, если исходить из того, что по ТЗ наружу должен торчать интерфейс который считает и логирует.<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838121'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T11:31:54+00:00">02.09.20, 11:31</time></span><div class='quote '>которая конвертирует температуру по Кельвину в температуру по Цельсию</div></div><br>
Так я не понимаю, какие проблемы? По аналогии напиши, в чем прикол то? Сложность в переименовании интерфейсов и классов возникла?]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838121</guid>
        <pubDate>Wed, 02 Sep 2020 11:31:54 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838121</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838118'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:52:33+00:00">02.09.20, 10:52</time></span><div class='quote '>Конечно, и что в этом плохого? Есть такой принцип: Принцип единственной ответственности буква S, из абрревиатуры SOLID, вот мы как раз ему и последовали. В чем косяк то?</div></div><br>
Принцип единственной ответственности не запрещает DI и не запрещает общаться с другими компонентами.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838120'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:57:14+00:00">02.09.20, 10:57</time></span><div class='quote '>Так я выше написал, что этот класс будет тестироваться с помощью интеграционных тестов.</div></div><br>
Ну т.е. все сводится к тому какой тест можно назвать юнит-тестом, а какой уже интеграционный. Вопрос не в сути, а в терминологии. При этом ради сохранения чистоты терминологии автор готов пойти на усложнение кода и, соответственно, добавление ошибок.<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838120'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:57:14+00:00">02.09.20, 10:57</time></span><div class='quote '>Если у тебя будет как ты выше написал CalculatorWithLogger, CalculatorWithDatabase, CalculatorWithLoggarAndDatabase, то тут в любом случае придется вводить интерфейс. Ты уже докапываешься до незначительных деталей ИМХО.</div></div><br>
И не просто так придется вводить интерфейс. Т.к. у тебя будет<br>
Calculator : ICalculator<br>
CalculatorWithLogger : ICalculator<br>
CalculatorWithDatabase : ICalculator<br>
CalculatorWithLoggarAndDatabase : ICalculator<br>
что, как ты понимаешь, легко может привести к ошибке.<br>
<br>
Для исключения ошибки тебе придется вводить еще один интерфейс:<br>
Calculator : ICalculatorUnit<br>
CalculatorWithLogger : ICalculator<br>
CalculatorWithDatabase : ICalculator<br>
CalculatorWithLoggarAndDatabase : ICalculator<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838120'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:57:14+00:00">02.09.20, 10:57</time></span><div class='quote '>Какая эта функция?</div></div><br>
которая конвертирует температуру по Кельвину в температуру по Цельсию]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838120</guid>
        <pubDate>Wed, 02 Sep 2020 10:57:14 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838120</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838117'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:39:14+00:00">02.09.20, 10:39</time></span><div class='quote '>Кстати, даже в этом коде есть логика, которую можно тестировать <br>
Либо ты должен проверять параметры конструктора и кидать исключение в случае если logger или calculator имеют нулевые значения. Либо ты должен проверять на ноль непосредственно при сложении. Т.е. тут цикломатическая сложность гарантированно больше 1, а значит надо делать тест. Можно конечно назвать этот тест интеграционным, но мне кажется, что это уже дрочерство на терминологию </div></div><br>
Так я выше написал, что этот класс будет тестироваться с помощью интеграционных тестов. Ну добавь туда проверку на null, если тебе так нужно, я же пример привел, а не конечное приложение.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838117'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:39:14+00:00">02.09.20, 10:39</time></span><div class='quote '>Да, вот только функция уровнем выше (которая будет использовать CalculatorWithLogger) ничего не должна знать про существование CalculatorWithLogger, ей известен только ICalculator... Т.е. либо тебе придется вводить еще одну абстракцию, либо ты рискуешь совершить ошибку передав в CalculatorWithLogger в качестве ICalculator другой CalculatorWithLogger.</div></div><br>
Если у тебя будет как ты выше написал CalculatorWithLogger, CalculatorWithDatabase, CalculatorWithLoggarAndDatabase, то тут в любом случае придется вводить интерфейс. Ты уже докапываешься до незначительных деталей ИМХО. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T10:59:18+00:00">02.09.20, 10:59</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838119'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:55:29+00:00">02.09.20, 10:55</time></span><div class='quote '>Проблема в том, что эта функция должна либо сама создать объект CalculatorWithLogger (для этого ей надо будет как-то получить ILogger и ICalculator), либо функция должна будет получить CalculatorWithLogger в качестве параметра (это насколько я понимаю, противоречит требованию к юнит-тесту)</div></div><br>
Какая эта функция? Я тебя не понимаю. Обработчик ГУИ формы? CalculatorWithLogger - это внешнее API, которые ты юзаешь в своем коде, а Calculator - это внутреняя бизнес логика, которая тестируется с помощью ЮТ.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838119</guid>
        <pubDate>Wed, 02 Sep 2020 10:55:29 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838119</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838116'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:34:22+00:00">02.09.20, 10:34</time></span><div class='quote '>В чем проблема написать такой тест? Ну возьми функции выше, измени названия классов. </div></div><br>
Проблема в том, что эта функция должна либо сама создать объект CalculatorWithLogger (для этого ей надо будет как-то получить ILogger и ICalculator), либо функция должна будет получить CalculatorWithLogger в качестве параметра (это насколько я понимаю, противоречит требованию к юнит-тесту)]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838118</guid>
        <pubDate>Wed, 02 Sep 2020 10:52:33 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838118</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838117'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:39:14+00:00">02.09.20, 10:39</time></span><div class='quote '>Замечетельно&#33; Вот только у тебя в системе один логгер и Х классов, которые должны что-то протоколировать. Таким образом твое решение приводит к удвоению количества классов </div></div><br>
Конечно, и что в этом плохого? Есть такой принцип: <a class='tag-url' href='https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF_%D0%B5%D0%B4%D0%B8%D0%BD%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9_%D0%BE%D1%82%D0%B2%D0%B5%D1%82%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8' target='_blank'>Принцип единственной ответственности</a> буква S, из абрревиатуры SOLID, вот мы как раз ему и последовали. В чем косяк то? :-? <br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838117'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:39:14+00:00">02.09.20, 10:39</time></span><div class='quote '>А если пойти еще дальше и к логгеру добавить... ну скажем запись в БД, при этом и запись в БД и логгер опциональны, то у тебя получается такой вот зоопарк: Calculator, Logger, Database, CalculatorWithLogger, CalculatorWithDatabase, CalculatorWithLoggarAndDatabase.<br>
<br>
Согласись, решение так себе...</div></div><br>
Никакого зоопарка не будет. Будет один интерфейс, от которого будут наследоваться все эти CalculatorWithLogger, CalculatorWithDatabase, CalculatorWithLoggarAndDatabase. Это вроде обычный подход, разве нет? :huh:<br>
А Calculator, Logger, Database - это вообще разные классы, реализующие разный функционал. Городить все это в один класс - это будет неверным.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838117</guid>
        <pubDate>Wed, 02 Sep 2020 10:39:14 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838117</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Либо создай класс LoggerCalculator, в котором например ты можешь логировать и считать сумму.<br>
Например на основе нашего кода выше:</div></div><br>
Замечетельно&#33; Вот только у тебя в системе один логгер и Х классов, которые должны что-то протоколировать. Таким образом твое решение приводит к удвоению количества классов ;)<br>
<br>
А если пойти еще дальше и к логгеру добавить... ну скажем запись в БД, при этом и запись в БД и логгер опциональны, то у тебя получается такой вот зоопарк: Calculator, Logger, Database, CalculatorWithLogger, CalculatorWithDatabase, CalculatorWithLoggarAndDatabase.<br>
<br>
Согласись, решение так себе... <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T10:52:08+00:00">02.09.20, 10:52</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Либо создай класс LoggerCalculator, в котором например ты можешь логировать и считать сумму.<br>
Например на основе нашего кода выше:</div></div><br>
Кстати, даже в этом коде есть логика, которую можно тестировать ;)<br>
Либо ты должен проверять параметры конструктора и кидать исключение в случае если logger или calculator имеют нулевые значения. Либо ты должен проверять на ноль непосредственно при сложении. Т.е. тут цикломатическая сложность гарантированно больше 1, а значит надо делать тест. Можно конечно назвать этот тест интеграционным, но мне кажется, что это уже дрочерство на терминологию ;)<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838116'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:34:22+00:00">02.09.20, 10:34</time></span><div class='quote '>Почему не удовлетворяет? Удовлетворяет. Все действия запротоколированны. Посмотри код выше. Юзать то ты будешь CalculatorWithLogger.</div></div><br>
Да, вот только функция уровнем выше (которая будет использовать CalculatorWithLogger) ничего не должна знать про существование CalculatorWithLogger, ей известен только ICalculator... Т.е. либо тебе придется вводить еще одну абстракцию, либо ты рискуешь совершить ошибку передав в CalculatorWithLogger в качестве ICalculator другой CalculatorWithLogger.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838116</guid>
        <pubDate>Wed, 02 Sep 2020 10:34:22 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838116</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838115'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:30:01+00:00">02.09.20, 10:30</time></span><div class='quote '>Такой калькулятор не удовлетворяет требованию, что все действия должны быть запротоколированы </div></div><br>
Почему не удовлетворяет? Удовлетворяет. Все действия запротоколированны. Посмотри код выше. Юзать то ты будешь CalculatorWithLogger.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838115'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:30:01+00:00">02.09.20, 10:30</time></span><div class='quote '>Отличное решение&#33;<br>
Пусть нас надо написать функцию, которая конвертирует температуру по Кельвину в температуру по Цельсию. Протестированный калькулятор у нас уже есть. Давай использовать его  Не забываем, что каждый вызов калькулятора должен быть запротоколирован логгером. Как должна выглядеть такая функция и тест к ней?</div></div><br>
В чем проблема написать такой тест? Ну возьми функции выше, измени названия классов.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838115</guid>
        <pubDate>Wed, 02 Sep 2020 10:30:01 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838115</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Потом ты реализуешь сам калькулятор, применяя опыт написанный выше, что функции должны быть без сайд эффектов и чистые, у тебя получится что то типа</div></div><br>
Такой калькулятор не удовлетворяет требованию, что все действия должны быть запротоколированы ;)<br>
<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Логировать ты можешь в другом месте, например на уровне выше. </div></div><br>
Отличное решение&#33; <br>
Пусть нас надо написать функцию, которая конвертирует температуру по Кельвину в температуру по Цельсию. Протестированный калькулятор у нас уже есть. Давай использовать его ;) Не забываем, что каждый вызов калькулятора должен быть запротоколирован логгером. Как должна выглядеть такая функция и тест к ней?]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838113</guid>
        <pubDate>Wed, 02 Sep 2020 10:13:44 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838113</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838109'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:38:19+00:00">02.09.20, 09:38</time></span><div class='quote '>Да. Но на практике выгоднее, когда у тебя отваливается все как можно раньше. ЮТ у нас, например, гоняются локально. Возможно, стоит так же часто гонять интеграционные, но это неудобно.</div></div><br>
Так в статье речь про TDD, а не про гоняния UT. Соответственно при разработке на основе TDD - ты тестируешь непосредственный функционал того, что ты реализовываешь, и ловишь ошибки сразу, ну либо после изменений.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838109'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:38:19+00:00">02.09.20, 09:38</time></span><div class='quote '>Еще раз. Так может быть. И поэтому действительно к мокам нужно осторожно относиться. Но вот представь, что мы все пишем так, как рекомендуется в статье, а потом, дополнительно, еще пишем ЮТ, где мокируем всякий ввод/вывод, работу с базой, сеть и пр. То есть делаем дополнительные проверки перед интеграционнымм, чтобы раньше узнать о проблемах. Я не понимаю, почему это плохо.</div></div><br>
Ээээ. Если мы пишем так как в статье, значит нам уже не надо писать дополнительно ЮТ. Мы с них начинаем писать. Пишем тест, потом функционал. А уж потом дополнительно пишем интеграционные тесты, где с помощью моков эмулируем различные сценарии.<br>
Ну и автор не говорит что нельзя моки юзать в ЮТ и все тут, он как бы намекает, что если в ЮТ используются Моки то это уже говорит о том, что модули сильно взаимосвязаны, и можно переписать куда лучше, чтоб избавится от моков.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838111'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:46:11+00:00">02.09.20, 09:46</time></span><div class='quote '>Интеррационный тест для того и нужен, чтобы проверить взаимодействие двух реальных объектов. Т.е. суть интергационного теста - как раз отсутсвие мока.<br>
</div></div><br>
С помощью моков можно и нужно моделировать различное поведение системы в тех или иных случаях. Вот и автор пишет по этому поводу:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><br>
When you use generic composition utilities, each element of the composition can be unit tested in isolation without mocking the others.<br>
The compositions themselves will be declarative, so they’ll contain zero unit-testable logic (presumably the composition utility is a third party library with its own unit tests).<br>
Under those circumstances, there’s nothing meaningful to unit test. You need integration tests, instead.<br>
</div></div><br>
Смысл в том, что если ты юзаешь какие то стандартные/универстальные утилиты композиции, то их нет смысла тестировать, и значит UT лишено смысла, по сути ты Моки тестируешь, у тебя код становится сильно связанным, тесты становятся взаимозависимыми. У тебя должны тестироваться отдельные части системы, а не все в куче. Все в куче - это уже интеграционный тест.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838111'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:46:11+00:00">02.09.20, 09:46</time></span><div class='quote '>Ну вот представим, что у тебя есть 2 компоненты: калькулятор и логгер. Все действия калькулятора должны быть запротоколированы. Как должен выглядить идеальный юнит-тест суммы? </div></div><br>
Ты для начала пишешь ЮТ, потом пишешь программу. <br>
Вот ты и пишешь например:<br>
<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">void SumTest()</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; ICalculator calc = new Calculator();</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; assertEqual(7, calc.Sum(3,4));</div><div class="code_line">&nbsp;&nbsp; ...</div><div class="code_line">}</div></ol></div></div></div></div><br>
<br>
Потом ты реализуешь сам калькулятор, применяя опыт написанный выше, что функции должны быть без сайд эффектов и чистые, у тебя получится что то типа:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">interface ICalculator</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; &nbsp;int Sum(int a, int b);</div><div class="code_line">}</div><div class="code_line">&nbsp;</div><div class="code_line">public class Calculator : ICalculator</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; public int Sum(int a, int b)</div><div class="code_line">&nbsp;&nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return a + b;</div><div class="code_line">&nbsp;&nbsp; }</div><div class="code_line">}</div></ol></div></div></div></div><br>
Логировать ты можешь в другом месте, например на уровне выше. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T10:19:57+00:00">02.09.20, 10:19</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838113'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T10:13:44+00:00">02.09.20, 10:13</time></span><div class='quote '>Логировать ты можешь в другом месте, например на уровне выше.</div></div><br>
Либо создай класс LoggerCalculator, в котором например ты можешь логировать и считать сумму.<br>
Например на основе нашего кода выше:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">public class CalculatorWithLogger</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp; private ICalculator _calculator;</div><div class="code_line">&nbsp;&nbsp; private readonly ILogger _logger;</div><div class="code_line">&nbsp;&nbsp; public CalculatorWithLogger(ICalculator calc, ILogger logger)</div><div class="code_line">&nbsp;&nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; _calculator = calc;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; _logger = logger;</div><div class="code_line">&nbsp;&nbsp; }</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; public int Sum(int a, int b)</div><div class="code_line">&nbsp;&nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;_logger.WriteLine($&quot;Call method Sum({a},{b})&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return _calculator.Sum(a, b);</div><div class="code_line">&nbsp;&nbsp; }</div><div class="code_line">}</div></ol></div></div></div></div> <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T10:21:50+00:00">02.09.20, 10:21</time></span></span><br>
Так вот этот класс CalculatorWithLogger - уже нет смысла тестировать с помощью UT. Потому что ты по сути будешь тестировать логгер(который уже тестируется в своей библиотеке) и Calculator, для которого уже и так написаны UT.<br>
А вот в интеграционном тесте - его есть смысл тестировать, подкидывая различные логгеры например. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T10:28:44+00:00">02.09.20, 10:28</time></span></span><br>
Вот автор об этом и пишет дальше:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><br>
That means that the code you use to set up network requests and request handlers won’t need unit tests. Use integration tests for those, instead.<br>
<br>
That bears repeating:<br>
<strong class='tag-b'>Don’t unit test I/O.<br>
I/O is for integrations. Use integration tests, instead.<br>
</strong><br>
<br>
<strong class='tag-b'>It’s perfectly OK to mock and fake for integration tests.</strong><br>
</div></div><br>
Статья конечно довольно большая. И если рассказывать в отрыве не понятно что к чему, но когда начинаешь читать, начинаешь понимать о чем он пишет.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838112</guid>
        <pubDate>Wed, 02 Sep 2020 09:48:26 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838112</link>
        <description><![CDATA[D_KEY: Да, давайте больше практики добавим в холивар :) Не политика жеж]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838111</guid>
        <pubDate>Wed, 02 Sep 2020 09:46:11 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838111</link>
        <description><![CDATA[Fester: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838108'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:00:26+00:00">02.09.20, 09:00</time></span><div class='quote '>Моки в ЮТ быть не должны, они должны быть в интеграционных тестах</div></div><br>
Интеррационный тест для того и нужен, чтобы проверить взаимодействие двух реальных объектов. Т.е. суть интергационного теста - как раз отсутсвие мока.<br>
<br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838108'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:00:26+00:00">02.09.20, 09:00</time></span><div class='quote '>А если они в ЮТ - то у тебя слабо декомпозирована система, и есть жесткие связи, без которых ты не можешь протестить функционал, что является кладезью ошибок. </div></div><br>
Ну вот представим, что у тебя есть 2 компоненты: калькулятор и логгер. Все действия калькулятора должны быть запротоколированы. Как должен выглядить идеальный юнит-тест суммы? :)]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838109</guid>
        <pubDate>Wed, 02 Sep 2020 09:38:19 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838109</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838108'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T09:00:26+00:00">02.09.20, 09:00</time></span><div class='quote '>Вот, а предполагается, что по хорошему, Моки в ЮТ быть не должны, они должны быть в интеграционных тестах, типа именно там их место.</div></div><br>
Да. Но на практике выгоднее, когда у тебя отваливается все как можно раньше. ЮТ у нас, например, гоняются локально. Возможно, стоит так же часто гонять интеграционные, но это неудобно.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>А если они в ЮТ - то у тебя слабо декомпозирована система, и есть жесткие связи, без которых ты не можешь протестить функционал, что является кладезью ошибок.</div></div><br>
Еще раз. Так может быть. И поэтому действительно к мокам нужно осторожно относиться. Но вот представь, что мы все пишем так, как рекомендуется в статье, а потом, дополнительно, еще пишем ЮТ, где мокируем всякий ввод/вывод, работу с базой, сеть и пр. То есть делаем дополнительные проверки перед интеграционнымм, чтобы раньше узнать о проблемах. Я не понимаю, почему это плохо.]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838108</guid>
        <pubDate>Wed, 02 Sep 2020 09:00:26 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838108</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838105'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T08:44:31+00:00">02.09.20, 08:44</time></span><div class='quote '>Мне кажется, что автор этого текста сам себя перемудрил </div></div><br>
Ну почему же. Просто он немного с другой стороны смотрит на это. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T09:02:16+00:00">02.09.20, 09:02</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838106'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T08:46:59+00:00">02.09.20, 08:46</time></span><div class='quote '>Ну так моки и помогают протестить в юнитах то, что без них можно будет тестить только в интеграционных тестах. Конечно, их не должно быть много. Но в абсолют я бы это не возводил.</div></div><br>
Вот, а предполагается, что по хорошему, Моки в ЮТ быть не должны, они должны быть в интеграционных тестах, типа именно там их место. А если они в ЮТ - то у тебя слабо декомпозирована система, и есть жесткие связи, без которых ты не можешь протестить функционал, что является кладезью ошибок.]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838106</guid>
        <pubDate>Wed, 02 Sep 2020 08:46:59 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838106</link>
        <description><![CDATA[D_KEY: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838081'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>korvin &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:32:06+00:00">01.09.20, 22:32</time></span><div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838080'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:01:51+00:00">01.09.20, 22:01</time></span><div class='quote '>Ну потому что при нормальной декомпозиции размер системы не должен настолько сильно сказываться.</div></div><br>
Как это не должен, когда должен: к юнит тестам добавляются интеграционные тесты, потом функциональные и системные.</div></div><br>
Ну так они полезны. И потому это стоит того. Альтернатива - ручное тестирование с регрессом на несколько человеко-месяцев :D <br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Самая ранняя из возможных — это хинты IDE от компилятора и анализатора.</div></div><br>
Эм. Согласен. Но я имел в виду самая ранняя из возможных для конкретного кейса.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Что он показывает, так проблемы анализа и постановки задач и вместо нормального решения затыкает костылём (собой).</div></div><br>
Каким боком тут анализ и постановка задач?<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838080'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:01:51+00:00">01.09.20, 22:01</time></span><div class='quote '>А если его применять сначала, то…</div></div><br>
…никогда не дойдёшь до реализации. Либо вместо тебя дойдут конкуренты по методу херак-херак и в продакшн, но это уже другая история.<br>
</div></div><br>
Ну вот хотелось бы понять, на чем это основано. Как раз обычно все эти быстрые стартапы часто активно используют эти &quot;новые&quot; хорошие инженерные практики, т.к. без них херак-херак превращается в ад.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838080'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:01:51+00:00">01.09.20, 22:01</time></span><div class='quote '>Начали использовать TDD, что помогло нам заметить проблемы.</div></div><br>
Не помогло. Добавило новых.<br>
</div></div><br>
Проблемы были и до этого, просто они были неявными. Мы их вытащили на поверхность, что позволит нам в стратегическом плане выиграть. Да, тактически может замедлить, но это повод исправлять проблемы, а не &quot;градусник&quot; хейтить.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Контракт этого кода: сумма удвоенных нечётных целых чисел из списка. Именно это в нём и написано. Дальше что?</div></div><br>
Простой пример. Начал рефакторить или оптимизировать, ошибся в чем-то. Сломал.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Зачем вы поправили код?</div></div><br>
Программисты такие, знаешь ли. Код правят. Делали фичу, рефакторили, оптимизировали - выбирай на свой вкус.<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838080'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:01:51+00:00">01.09.20, 22:01</time></span><div class='quote '>найти и исправить все места, где этот код используется в соответствии с новым контрактом.</div></div><br>
Это ещё с какого хера? Если у этих мест появились новые требования (новый контракт), пусть сами его использование и чинят. Моя задача, как реализатора контракта — реализовать его.</div></div><br>
Да. А ты при реализации или случайно или специально его нарушил. Как без тестов это понять?<br>
<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838080'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>D_KEY &#064; <time class="tag-quote__quoted-time" datetime="2020-09-01T22:01:51+00:00">01.09.20, 22:01</time></span><div class='quote '>И я думаю, что многих из этих проблем не было бы при использовании TDD со старта.</div></div><br>
Что ж, удачи тебе. )</div></div><br>
Ну я не скоро еще буду что-либо стартовать :D <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2020-09-02T08:53:17+00:00">02.09.20, 08:53</time></span></span><br>
<div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838098'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Wound &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T06:54:05+00:00">02.09.20, 06:54</time></span><div class='quote '>Основная идея в том, что если у тебя есть Моки, значит у тебя тесная связь, и твоя функция/система зависит от чего то извне, без чего не может быть протестирована, а это типа херово. ... Типа моки нужно применять в интеграционных тестах, и весь функционал, которые не покрывают UT - подразумевается что он должен работать с IO, соккеты/файлы/чета там еще, поэтому это тистируется интеграционными тестами. Ну это как я понял из статьи выше.</div></div><br>
Ну так моки и помогают протестить в юнитах то, что без них можно будет тестить только в интеграционных тестах. Конечно, их не должно быть много. Но в абсолют я бы это не возводил.<br>
<br>
А вот с этим я скорее согласен:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '>Надо писать код в функциональной парадигме, чтоб этого избегать, чистые функции(без сайд эффектов), всякие там монады(then().then().then...) и т.п.</div></div>]]></description>
        <author>D_KEY</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838105</guid>
        <pubDate>Wed, 02 Sep 2020 08:44:31 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838105</link>
        <description><![CDATA[Fester: Мне кажется, что автор этого текста сам себя перемудрил :)<br><br>Взаимодействие происходит по какому-либо (заранее известному) контракту, который описывается неким интерфеском. Юнит, соответственно, не взаимодействует ни с какими внешними объектами, он взаимодествует с контрактами. Более того, юнит должен исходить из того, что контракты работают так, как описано.<br><br>А список &quot;слабых связей&quot; жесть:<br>&gt;&gt; Module imports without side-effects (in black box testing, not all imports need isolating)<br>Не совсем понимаю, что это такое<br><br>&gt;&gt; Message passing/pubsub<br>А потом тестировать switch, который будет разгребать эти сообщения.<br><br>&gt;&gt; Immutable parameters (can still cause shared dependencies on state shape)<br>Ага и по 100 параметров в каждой функции. Ну нахрен.]]></description>
        <author>Fester</author>
        <category>Holy Wars</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838102</guid>
        <pubDate>Wed, 02 Sep 2020 08:04:20 +0000</pubDate>
        <title>TDD vs не TDD</title>
        <link>https://forum.sources.ru/index.php?showtopic=419507&amp;view=findpost&amp;p=3838102</link>
        <description><![CDATA[Wound: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=419507&view=findpost&p=3838100'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Fester &#064; <time class="tag-quote__quoted-time" datetime="2020-09-02T07:51:18+00:00">02.09.20, 07:51</time></span><div class='quote '>Не знаю, наверное я не понял всей мысли, но эта мысль кажется мне странной  Я уж не говорю о том, что Мок-объекты заменяют итерфейсы, а не объекты (D из SOLID).</div></div><br>
Ну вот автор и приводит пример.<br>
Типа можно ли протестировать модуль/функцию без имитации зависимости? Если нельзя - то это эта функция/модуль - тесно связана с имитируемыми зависимостями. Соотвественно получается что Моки и DI - являются тесной зависимостью. Чем больше зависимостей - тем больше вероятность получить ошибку.<br>
Вот тут он это описывает:<br>
<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <div class='quote '><br>
Ironically, most of the sources of coupling are mechanisms originally designed to reduce coupling. That makes sense, because in order to recompose our smaller problem solutions into a complete application, they need to integrate and communicate somehow. There are good ways, and bad ways. The sources that cause tight coupling should be avoided whenever it’s practical to do so. The loose coupling options are generally desirable in a healthy application.<br>
<strong class='tag-b'>You might be confused that I classified dependency injection containers and dependency injection parameters in the “tight coupling” group, when so many books and blog post categorize them as “loose coupling”. Coupling is not binary. It’s a gradient scale. That means that any grouping is going to be somewhat subjective and arbitrary.<br>
I draw the line with a simple, objective litmus test:<br>
Can the unit be tested without mocking dependencies? If it can’t, it’s tightly coupled to the mocked dependencies.<br>
The more dependencies your unit has, the more likely it is that there may be problematic coupling. </strong>Now that we understand how coupling happens, what can we do about it?<br>
</div></div>]]></description>
        <author>Wound</author>
        <category>Holy Wars</category>
      </item>
	
      </channel>
      </rss>
	