Обновить
8K+
53
Alex Gusev@flancer

Я кодирую, потому что я кодирую…

9,2
Рейтинг
99
Подписчики
Отправить сообщение

Вот я и считаю, что достаточно функционального тестирования для проверки работоспособности модуля/приложения. Юнит-тестирование избыточно. Оно создаёт ложное ощущение контроля ситуации, не предоставляя таковой по сути. Нам не нужно проверять всё, нам нужно проверять только то, что действительно важно, на что есть спецификация (требования).

Возможно ли функциональное тестирование отдельного класса? Если да, то чем функциональное тестирование отдельного класса отличается от юнит-тестирования отдельного класса?

Модуль в данном контексте это что — функция, класс, скрипт, набор скриптов? Как задаётся нужное состояние модуля, чтобы протестировать конкретное управляющее воздействие?

Тем не менее, они что-то проверяют, в отличие от. А что проверяют юнит-тесты?

В этой статье написано:


Первое, что придется сделать для обеспечения качества, это забрать функцию контроля у разработчиков и нанять человека, который будет за него отвечать.

По мере разрастания проекта, времени на ручное тестирование будет оставаться все меньше и меньше…

Отсюда логически вытекает необходимость автоматизировать работу тестировщиков…

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

а затем змея начинает кусать свой хвост:


На практике чаще всего написанием юнит-тестов для собственного кода занимается сам разработчик.

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


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


В статье пропущен шаг функционального тестирования, а я считаю, что это — минимальный уровень, на который есть смысл опускаться. Если есть функциональные тесты и выше, то юнит-тесты просто не нужны. Зачем проверять, как работают отдельные буквы, если получаются нужные слова, из которых выстраиваются правильные предложения?


До появления юнит-тестов рефакторинг делали невзирая на наличие тестов, довольствуясь ручной проверкой, затем проверку стали автоматизировать, затем появились функциональные и интеграционные тесты, а потом решили получить 100% code coverage и вышли на unit-тесты.


Простой вопрос, считаете ли вы, что полноценное юнит-тестирование должно на 100% покрывать код проекта?


Если вы не гонитесь за 100% code coverage unit-тестами, то мы с вами, скорее всего, имеем в виду одно и то же под разными названиями (вы называете это юнит-тестами, я — функциональными тестами).

Вы же понимаете, что до появления юнит-тестов рефакторинг как-то делали?

Изменяете код и проверяете, что он отрабатывает так, как вы ожидаете. Если в вашем проекте вы не можете делать это без юнит-тестов, то рефакторьте с юнит-тестами. Если можете проверить без юнит-тестов — рефакторьте без.

В сложных системах код отдельных фрагментов, которые могут быть покрыты юнит-тестами, местами достаточно примитивен. Поэтому юнит-тесты вырождаются до набора моков, проверяющих, что "А дёргает Б, после чего дергается В и Г" (я эту мысль пытался раскрыть в "Unit-тестирование в сложных приложениях"). Так что лучше как-раз таки оставить функциональные тесты, т.к. юнит-тесты не выявляют имеющихся проблем, а только свидетельствуют о том, что проверяемый фрагмент кода работает так, как думает, что так и должен работать этот фрагмент, программист, его написавший (это особенно характерно для TDD). Т.е., 99% покрытие кода юнит-тестами не говорит о том, что код работает правильно, а всего лишь о том, что тесты обнаружат изменения в покрытом коде, если он будет изменён без соответствующего изменения тестов.


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

Такая возможность языка провоцирует небрежность в разработке. Разработчик кода предположил, что метод "foo" должен быть приватным, а вам вдруг понадобилось в своём коде дёрнуть этот приватный метод как публичный. Ну вы и дёрнули. Вместо того, чтобы обратиться к разрабу и сказать, что его вИдение прекрасного не так уж и совершенно. Эта особенность языка python помогает кодерам думать, что они более сообразительные, чем есть на самом деле, вместо того, чтобы делать код более совершенным. Для кого-то это хорошо, кому-то — не очень.

Пример проведения стендапа

Хорошо, что их там только 11. На весь процесс уйдёт всего лишь 11 * 2 = 22 минуты. Интересно, а какова верхняя граница кол-ва участников команды, после которой её выгоднее разбить на две и проводить стендапы параллельно?

У меня на ноуте не настроен cron для Magento. А прямо в базу я пишу потому, что так действительно быстрее. Плюсом идёт, что я могу заливать данные в БД без использования кода Magento в принципе. Хоть sql-скриптами. Использование классов Magento, в том числе и \Magento\Catalog\Model\Product\Gallery\CreateHandler, я рассматривал в предыдущей статье.

Получается, у нас есть два типа объектов.
  • Жесткие объекты содержат только методы. ...
  • Мягкие объекты данных содержат только данные. ...

интересная мысль, отсылающая нас к Гарвардской архитектуре ЭВМ.

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


Допустим, я интегрирую ERP-систему и e-commerce систему. Это разные предметные области с разными моделями (данных в первую очередь, и предметной области во вторую). Я не создаю новую, обобщённую модель предметной области (или обобщённую модель данных) для результата композиции двух систем. Я в каждой системе работаю со своей моделью данных / моделью предметной области, производя реструктуризацию данных из одной модели в другую на стыке двух систем.


Граница между ERP-системой и e-commerce системой аналогична границе между UI и API при построении гридов, только масштаб другой. Данные мигрируют между различными областями, меняя свою структуру, но предметные области при этом не смешиваются. Реализация функционала для приложения "Банкинг" может потребовать выделения различных предметных областей в рамках одной информационной системы (UI, обработка, хранение). Да взять хотя бы версионирование процессов в BPMS, когда различные версии одного и того же бизнес-процесса оперируют с различным набором данных и имеют разное количество шагов. При этом различные предметные области (по версиям процесса) сосуществуют совместно в рамках одной информационной системы (правда между этими областями не происходит обмен данными, они параллельны в своём существовании).


В общем, спасибо за подкинутый материал. Было интересно помозговать на тему :)

Если разделять "модель данных" и "модель предметной области", то тогда нужно чётко фиксировать границы этой самой "предметной области" (границы применимости моделей). Я также допускаю, что в рамках одного приложения с одной моделью данных могут работать различные модели предметной области. В зависимости от того в какой проекции обрабатываются элементы этой модели данных (UI, API, validation, ACL verification, business processing). Например, грид на UI'е может работать с моделью предметной области "User Interface" (строки-столбцы), являющейся комбинацией различных элементов модели данных (номер заказа, имя клиента, ...). По большому счёту, гриду всё равно, из каких источников поднимаются в него данные (БД, файлы, внешний запрос), в его мире (области) все предметы — это строки, столбцы, рендереры, валидаторы, фильтры и т.п. Допустим, мы подтягиваем в своё приложение библиотеку/модуль для построения гридов, тогда мы должны имеющиеся в проекте данные представлять в виде, понятном для соответствующей предметной области (гридов). Получается, что у нас приложение разделяется на некоторое кол-во областей (представление данных, ввод-вывод, верификация, обработка, хранение, выборка) между которыми данные дрейфуют, преобразовываясь из одной структуры в другую. Да, кстати, и моделей данных у нас может быть множество. По большому счёту, для каждого внешнего приложения, с которым наше обменивается данными, присутствует своя "модель данных". И мы опять должны реструктурировать данные при передаче/получении в/из внешнего приложения из нашей структуры (наша модель данных о Клиенте) в структуру, понимаемую внешним приложением (их модель данных о Клиенте).


Это так, мысли вслух, чтобы ещё больше запутаться самому и запутать остальных.

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


“Архитектура с анемичной моделью” не что иное как процедурный подход к созданию архитектуры приложений в котором модель предметной области размазана по всему приложению

Но на это можно посмотреть и так, что в приложении есть чисто данные — данные без поведения, а есть слой кода, который имплементирует бизнес-логику, которая оперирует данными так или иначе. И этот слой может быть создан как в процедурном стиле, так и в объектно-ориентированном. Таже можно размазать этот слой по всему приложению или сконцентрировать в отдельные группы (controllers, helpers, services).


В таком случае мы в рамках одного приложения получаем то, о чём коллега lohmatii чуть выше говорил, как о "концептуальной модели данных" конкретного предприятия в рамках "большого бизнеса". Только тут мы имеем дело с "концептуальной моделью данных отдельного приложения" — она может быть формализована (сохранена в конкретной структуре в БД или файлах), а её проекции использоваться отдельными бизнес-функциями (процедурными или ОО). Хоть той же кнопкой "Снять наличные", если эта кнопка хоть что-то использует из "концептуальной модели данных приложения" (что маловероятно).

Это единое формализованное описание, которое ближе к бизнесу, чем к ИТ.

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


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

Вы абсолютно правы.

Сначала описываем процесс обработки абстрактных данных

и


но абстрактные данные я не могу вообразить

Вообразить. Вы можете описать процесс обработки того, чего не можете вообразить. Вообразить, а не обработать. Не соскакивайте с вектора.

Сначала описываем процесс обработки абстрактных данных

Тем не менее, вы можете описать процесс обработки того, чего вообразить не можете.

Информация

В рейтинге
836-й
Откуда
Рига, Латвия, Латвия
Дата рождения
Зарегистрирован
Активность

Специализация

Фулстек разработчик
Ведущий
От 3 000 €
JavaScript
HTML
CSS
Node.js
Vue.js
Веб-разработка
Progressive Web Apps
PostgreSQL
MySQL
GitHub