Обновить
26
ApeCoder@ApeCoder

Разработчик

6
Подписчики
Отправить сообщение

Это не "чисто математическое свойство связанное с утройством системы" рабиение программы на модули в основном связано с тем, как нам удобно думать о программе.


Человек не может держать в оперативной памяти и оперировать больше определенного количетва объектов (кошелек Миллера). Поэтому он разбивает задачу на куски. Эти куски будут частью языка предметной области.


Хорошая программа должна быть тоже структурирована из независимых кусков.


Если куски независимы то в терминах этих кусков просто писать тесты — не надо париться сразу и в одном месте со многими аспектами.


Тесты есть формализованное выражение требований. Структура программы, в-основном, должно быт формализованным выражениям подмножества языка предметной области.


На хорошем языке должно быть удобно формулировать требования. см также Ubiquitous Language.

Нет вы не поняли — если у кого-то такие уборщицы, то он работает в говноконторе. У меня другие уборщицы. Тесты тоже можно писать плохо и плохо интерпретировать фидбек от них. Всему надо учиться.


Вместо того, чтобы тупо делать мок надо сначала подумать.


о с тестами и советами уборщицы это никак не связано.

Примеры связаны с тестами — они их иллюстрируют. Проиллюстрируйте пожалуйста.


P.S. Хинт: если поставить галочку MarkDown внизу сообщения, то хабр будет фофрмлять знак > в начале строки как цитату.

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

В рамках конкретного теста можно исключить зависимости которые ему не нужно. Работа с ними будет протестирована другими тестами.

Программа выражает понятия некоторой предметной области. Чем более прямо выражает тем лучше.

В юнит тесте мы проверяем X на то, что если мы передали IY, то он делает то, что должен. IY это что-то, соблюдающее контракт IY, в частности Y.


Если мы кладем двигатель на стенд и подаем туда топливо из тестового стенда — это юнит тест двигателя.


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


И как тогда назвать тесты, которые проверяют взаимодействие модулей друг с другом в рамках одного процесса?

Фаулер считает что эти понятия размытые


Sociable and Solitary
Some argue that all collaborators (e.g. other classes that are called by your class under test) of your subject under test should be substituted with mocks or stubs to come up with perfect isolation and to avoid side-effects and a complicated test setup. Others argue that only collaborators that are slow or have bigger side effects (e.g. classes that access databases or make network calls) should be stubbed or mocked.

Occasionally people label these two sorts of tests as solitary unit tests for tests that stub all collaborators and sociable unit tests for tests that allow talking to real collaborators (Jay Fields' Working Effectively with Unit Tests coined these terms). If you have some spare time you can go down the rabbit hole and read more about the pros and cons of the different schools of thought.

Я иногда называю и тесты которые тестирую интеграцию со внешними системами интеграционными, и тесты, которые тестируют какие-то связки модулей интеграционными. Так же юнит тест может использовать production реализацию зависимости, если она проста для употребления, но это будет юнит тест.


Talking about different test classifications is always difficult. What I mean when I talk about unit tests can be slightly different from your understanding. With integration tests it's even worse. For some people integration testing is a very broad activity that tests through a lot of different parts of your entire system. For me it's a rather narrow thing, only testing the integration with one external part at a time. Some call them integration tests, some refer to them as component tests, some prefer the term service test. Even others will argue, that all of these three terms are totally different things. There's no right or wrong. The software development community simply hasn't managed to settle on well-defined terms around testing.

Don't get too hung up on sticking to ambiguous terms. It doesn't matter if you call it end-to-end or broad stack test or functional test. It doesn't matter if your integration tests mean something different to you than to the folks at another company. Yes, it would be really nice if our profession could settle on some well-defined terms and all stick to it. Unfortunately this hasn't happened yet. And since there are many nuances when it comes to writing tests it's really more of a spectrum than a bunch of discrete buckets anyways, which makes consistent naming even harder.

Интеграционный тест — это тест который проверяет, как части работают вместе. То что часть X вместе с Y делает что-то полезное. Если мы заменяем часть Y на тестовый сабкласс тест очевидно не тестирует интеграцию частей нашей системы а только то, что часть X соблюдает свой контракт.


Так как Y не является частью системы.


А вот, например шор определяет так:


James Shore


Focused Integration Tests

Unit tests aren't enough. At some point, your code has to talk to the outside world. You can use TDD for that code, too.

A test that causes your code to talk to a database, communicate across the network, touch the file system, or otherwise leave the bounds of its own process is an integration test. The best integration tests are focused integration tests that test just one interaction with the outside world.

ILogger это часть интерфейса SUT, а не реализация. Так что прибитость к ILogger это ok.


SUT не может интегрироваться с ILogger так как он интерфейс. А не другой юнит — это просто описание контракта и все.

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

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


Зачем вообще тестировать? "Надо просто тремиться к тому", чтобы код был безошибочный.


Зачем видеть ошибки комплияции? "Надо просто тремиться к тому", чтобы код был сразу правильный.

Завивит от того, что вы называете моком. Если SUT требует ILogger то передать ему InMemoryLogger а потом узнать у InMemoryLogger что в нем лежит — не будет прибитостью к реализации

Чтобы уменьшить количество зависимостей надо либо исключить какие-то действия в принципе (что делать нельзя),

Почему нельзя? Зачем тесту проверяющему правильность расчета (или интеграции расчетного модуля) проверять сразу и базу и логгирование.


Вообще говоря если задача модуля интеграция других модулей то его можно покрыть интеграционными тестами см focused integration tests

Разщумеется. Тесты это выражение требований. Структура программы — это язык на котором вы их выражаете. Если выражать требования на составленном вам языке неудобно, то язык неадекватен.


Вы же не пишете тесты с названиями типа


"Если на вход подать 2 функция должна возарвтить 3"?

Уборщицу, которая вам указывает, когда приходить на работу, а когда — уходить, тоже можно слушать либо нет.

Я скорее всего пришлушаюсь к совету уборщицы. Потому, что я не работаю в говноконторе, где она советует это делать просто так. Если она мне посоветует не приходить на работу, скорее всего там какая-нибудь дератизация или что-то еще.


Ответ простой — используемый подход к тестированию плохо согласуется с архитектурой вашей системы.

Тут хотелось бы пример: может быть это вы просто не видите возможностей упростить систему, так же как не увидели возможность, что уборщица дает стоящий совет.

Взаимосвязи есть наш способ видеть предметную область, а не только свойство предметной области. Тесты говорят "делай менее связано".


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


Если вы сформировали хорошую, годно мапающуюся на предметную область структуру, а потом видоизменяете ее, чтобы было «проще тестировать» — это неправильно.

Вот тут хотелось бы пример

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

С чего вы решили что оно никак не связанное?

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

Называется «мозг».

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


Мозг позволяет проверять систему на соответствие архитектуры тем или иным свойствам, а вот юнит-тесты — нет.

А слабо привести аргументы?

Не путайте «Мне нужен вот такой халат, но с перламутровыми пуговицами» и «Мне нужен халат, такой же, как этот халат сейчас, но с перламутровыми пуговицами». Второе не имеет с наследованием ничего общего, первое в программировании грозит неожиданными изменениями.

Это и есть наследование в определении UML notation guide кажется.
И такое наследование есть javascript и self


А если халат с перламутровыми пуговицами пошить после изменений халата-образца без перламутровых пуговиц, то неожиданные изменения проекта будут даже в жизни.

Это не значит что это не наследование, это значит, что таоке наследование более непредсказуемо чем наследование при обобщении.


Если сумасшедший генетик вернётся в прошлое и сделает так, чтоб млекопитающие кормили детёнышей смесью только воды, солей и белка

Нифига. Кошка будет кормить молоком или чем-то похожим. Потому, что приспособится к тем же условиям. У кошки никогда не было предка, который был "просто млекопитающее". Сначала вместо молока был питательный пот. Природа делает среднее ухо и челюсти из жабер.


Может быть несколько разных классификаций одного и того же в зависимости от целей.

Это вы про наследование при обобщении. Просто оно популярнее, потому, что привычнее и вам кажется что другого не бывает. Наследование при прототипировании это "Мне нужен халат как такой, но с перламутровыми пуговицами". То есть не "Все жители Москвы такие" а "Жители Москвы такие, если я не скажу обратного".

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


Если есть обобщение то есть и наследование (кошка наследует все свойства общие для всех живтоных). Обратное — неверно (прототипное наследование не является обобщением, например "Типичный житель Москвы обладает карими глазами. Вася — совсем как типичный житель Москвы, только глаза голубые")

Информация

В рейтинге
Не участвует
Откуда
Россия
Дата рождения
Зарегистрирован
Активность