Информация об изменениях

Сообщение Re[23]: Что такое Dependency Rejection от 23.12.2023 12:52

Изменено 23.12.2023 18:52 Pauel

Re[23]: Что такое Dependency Rejection
Здравствуйте, ·, Вы писали:

P>>Моки изначально предназначались для тестов вида "вызываем вон то, вон так, в такой последовательности"

·>Может быть. Неясно какое это имеет значение сейчас, так исторические курьёзны. Даже если посмотреть на историю библиотек для тестов — за много лет много чего менялось и переделывалось.

И сейчас это основной кейс для моков. Вы и сами тащите "надо проверить old и new", и другого варианта не видите, как будто его нет. Можно же и дизайн поменять, что бы юнитами такое проверять. Но нет — вы топите за моки.

P>>·>Причём тут перемножают? Это диктуется требованиями. Если в json тебе нужен b64, а аналогичном месте protobuf тебе нужен Bytes, то хоть на bf пиши, у тебя будут комбинации.

P>>У вас — охотно верю.
·>Потому что у нас не хелловорды, а не как у вас, да?

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

P>>Я вам пример приводил, про время, вам он ожидаемо не понравился — язык не тот

·>Я не понял к чему ты скачешь с одного на другое. Обсуждали статью и MaitreD, потом crypto api, теперь вот ещё time api зачем-то...

Со статьё давно всё ясно. crypto api и time это пример, которые показывают, за счет можно отказаться от моков, и что будет, если этого не делать.

P>>·>Так в изначальном дизайне crypto так и было — создаём hmac нужного алгоритма, потом выводим в нужном представлении. Ты почему-то упаковал это в одну функцию и назвал успехом.

P>>В данном случае мне не надо переживать за поломаные тесты, если понадобится другой алгоритм, другая либа, итд.
P>>Вот понадобился не hmac а что другое — в файлике samples поменял десяток значений, и всё
·>Почему десяток? У тебя только десяток операций в api?

Это у вас на моках упадут все тесты всех операций апи. О том и речь. А на обычных юнит-тестах вы подкидываете новый набор значений, и всё путём.

P>>А ваша альтернатива этому — еще и тесты перебулшитить.

·>Один, скорее всего. Ибо одного теста достаточно чтобы зафиксировать логику вычисления hmac. В остальных тестах достаточно ассертить его наличие, но не конкретный формат.

Ага, тесты "как написано" Вам придется написать много больше, чем один тест — как минимум, пространство входов более-менее покрыть. Моками вы вспотеете это покрывать.

P>>Ну да, этож только у вас сложные системы.

·>Ну да, сам же сказал, что у тебя всё помещается в один файлик. Или он гиговый?

Вы там в телепатию заигрались? Что именно по вашему помещается в один файлик? Вся система, все тесты, вся система с тестами?
Вы чего то недопоняли, но вместо уточнения начинаете валять дурака?

·>Какой негатив? Вроде говорили об одном, теперь чего-то новое.

·>Вообще неясно причём тут time api и причём тут моки и тестирование вообще.

time api это пример дизайна, как можно уйти от комбинаторного взрыва.

P>>Успокойтесь — это все статически контролируется, только в вашу джаву такие фичи еще не завезли.

·>Спасибо, но сводить всё к массиву из 7 чиселок — это фигня полная и издевательство. Даже такое DateTimeOffset.from({...time.toFields, ...date.toFields(), offset: serverOffset}); — и всё поехало. И где наносекуды, интересно?

Где вы видите массив? Это объект, статически типизированый, наносекунды будут в time.toFields как fractionalSeconds. Вам телепатия еще не надоела?

·>Конструкторы удобнее и надёжнее с нужными типами, например, OffsetDateTime.of(date, time, offset), это хотя бы читабельно, и если что-то не так, не компиляется


Принципиальное отличе of вместо from

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

·>Это твои фантазии.

Вы сами пишите, что тестировать надо "как написано", это следует из того, как вы предлагает решать задачу с hmac. Таких же задач будет не одна на проект, а целая куча. Вот и будут тесты "проверить что делает"

P>>Ну да — для вас перебулшитить тесты проблемой не является Еще и настаиваете, что так и надо.

·>Я настаиваю, что так не надо.

Если не надо, то должен быть другой подход к тестированию. А вы выбираете тесты на моках "проверим что вызывается hmac с нужными параметрами"

P>>Проходит же. Вот я и интересуюсь, кто настрочил горы непотребства

·>Вчерашние студенты?

Да не похоже.

P>>Эта разновидность тестов нужна и вам.

·>Нужны, но не для проверки каждой строчки кода, что параметры вызова не перепутаны. А только для тестирования интеграции.

АПИ и есть та самая интеграция.

P>>Продукт, система, приложение, апи, компонент, модуль. Для теста именно кода у нас другие инструменты — код-ревью, линт, дизайн-ревью, статические анализаторы, итд.

·>Я сказал "Они отменяют необходимость написания тучи этих самых xxxComposition, нет кода — нечего тестировать". Ты прикопаться решил к слову код? Ок, пусть будет не код, а модуль-компонент.
·>"Моки отменяют необходимость написания тучи этих самых xxxComposition, нет такого компонента|модуля — нечего тестировать." Так яснее?

Не отменяют. Когда вы укрупняете компонент, то тестировать его сложнее. Или ваше покрытие будет решетом, или вам придется понаписывать много моков вида "это вызывает то", которые сломаются даже при минорных изменения компоненты

P>>Можно. И это делается без моков. Если мы заложимся на значение или состояние, то получим куда больше гарантий.

·>Без моков ты предложил только полный запуск всей аппликухи, в лучшем случае с тестовой субд. Kafka/amps/lbm/solace/tibco/etc, кстати, тоже тестовую будешь пускать? Или как?

Вы додумываете. Это в вашем понадобился бы запуск всей апликухи. У меня же апликуха запускается только ради e2e тестов.
Кафка — это обычный эвент, как вариант, можно обойтись и простым юнитом, убедиться что функция возвращает объект-эвент.

P>>В функции средний девелопер может понаделывать ошибок куда больше, чем перепутать old и new.

·>Я в этом и до среднего не дотягиваю, дохрена таких ошибок делаю, но вся эта фигня на раз ловится тестами, c моками (стабами), да.

Если вы написали тест на old и new, то конечно же словится. Только откуда следует, что это единственные проблемы?

P>>Именно! А потому нам все контроллеры нужно тестировать в апи тестах — тем самым мы исключаем добрый десяток классов проблем.

·>И эти тесты дадут тебе гарантию?

Разумеется, мы ради этого и пишем тесты. Не только что бы убедиться, что работает здесь и сейчас, но что бы можно было перепроверить это в т.ч. на живом окружении.
После билда работает, после деплоя — нет, опаньки!
Впрочем, в прошлом годы вы рассказывали, что деплой трогать низя — он у вас хрупкий, не дай бог повалится от лишнего запроса.


P>>Что вас смущает? deep.eq проверит всё, что надо. query это не строка, объект с конкретной структурой, чтото навроде

P>>
P>>{
P>>  sql: 'select * from users where id=?',
P>>  params: [id],
P>>  transformations: {
P>>     in: [fn1],
P>>     out: [fn2]
P>>  }
P>>}
P>>

·>Жуть. Ну ладно. Т.е. тут мы тестируем репозиторий и ассертим текст sql

Здесь мы тестируем построение запроса

·>Как проверить, что текст запроса хотя бы синтаксически корректен?


Для этого нам всё равно придется выполнить его на реальной бд. Расскажите, как вы решите задачу вашими моками.

> И что он при выполнении выдаст то, что ожидается?


А здесь как вы моками обойдетесь?

> И как ты собрался тут подменять субд? Ты обещал, что теперь эту хрень можно отдать любой db и оно выдаст одинаковый результат? Даже если эта субд это oracle или cassandra? Да там синтаксис банально другой.


А разве я говорил, что бд можно менять любую на любую? Построение запросов мы можем тестировать для тех бд, которые поддерживаются нами.

P>>Сами трансформации тестируются отдельно, обычными юнитами, например expect(fn1(user)).to.eq(user.id);

·>Так ведь надо трансформировать не некий user, а конкретно ResultSet возвращённый из "select *". Что колоночки в select местами не перепутаны, как минимум.

Что вас смущает? трансформация результата принимает ResultSet и возвращает вам нужный объект.

·>Ещё это всё "красиво" только на твоих хоумпейдж проектах. В реальном коде эти sql будут сотни строк с многоэтажными джойнами и подзапросами, и такие "тесты" станут даже немножечко вредить.


Расскажите, как вы это моками решите

P>>Вы все думаете в единицах старого дизайна, когда БЛ прибита гвоздями к бд.

·>Не к бд прибита. БЛ прибивается к репе.

Это одно и то же, и в этом проблема. Я ж вам говорю, как можно иначе — но вы упорно видите только вариант из 90х-00х
В новом подходе не надо БЛ прибивать ни к какой репе, ни к бд, ни к стораджу, ни к кафе, ни к внешним сервисам

P>>Шота я этого за 4 года не заметил

·>Может у тебя проекты написанные вайтишниками после курса ML, я не знаю. Но у тебя есть целый гитхаб, погляди насколько часто и для чего Object используют.

Я как раз с гитхаба и брал, если что.

P>>Юзеру так и скажете — мы не можем вернуть ваши деньги, потому что у нас в конфигурации возвраты отключены.

·>Для этого и есть L1 support — "проверьте, что ваш компьютер включен".

Я именно это сказал — L1 support так и скажет юзеру, "в конфиге отключено, значит неположено"

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

P>>Добавили, посмотрели дифом, вкомитали. Вам же не надо сразу всё обрабатывать.

·>А в дифе 10к строчек отличаются. И как это смотреть? Аудит же пишется для каждой операции, т.е. каждого теста, да ещё и не по разу.

А почему 10к а не 10к миллионов?

P>>Если апи возвращает то, что надо, это значит что у вас связка конфиг-di-sl-рантайм-переменные-итд склеено правильно.

·>И это ты предлагаешь гонять на каждый "updateUser(newUser, oldUser)"? Спасибо, не надо нам такого щастя.

Да, я в курсе, у вас есть L1 суппорт, который скажет клиенту, что возвраты не положены.
Это не шутка — мне так L1 однажды залепил
Неделя бодания и перекинули проблему наверх, только когда я сослался на федеральный закон
Признавайтесь, ваша идея?

P>>Можно. Это старый подход.

·>Ты говоришь как будто это что-то плохое. Это разумный подход. Делить не по тому, что сейчас у фаулеров в моде, а по конкретному осязаемому критерию, т.к. это напрямую выражается во времени запуска и требуемых ресурсов для тестирования.

В данном случае вам нужно писать больше кода в тестах, и они будут хрупкими. Другого вы с моками не получите. Потому и убирают зависимости из БЛ целиком, что бы легче было покрывать тестами

P>>Это новый подход, позволяет обходиться без моков-стабов итд и свести тестирование ключевых вещей к дешовым юнит-тестам

·>У тебя тривиальное updateUser(newUser, oldUser) не тестируется юнитами. Любая мелочёвка требует запуска всего, в лучшем случае с in-mem субд.

Ага, сидим да годами ждём результаты одного теста. Вам самому не смешно?

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

·>С такими же гарантиями можно и просто метод дёргать. Аннотации это только от плохого дизайна.

Ну вот подергали вы метод. А потм вас попросили отразить всё такое в сваггере каком, что бы другим было понятно. Гы-гы. Ищите строчки в коде.
А с аннотациями взял да и отрендерил манифест.

P>>В этом случае можно сделать аудит через тесты состояния. Прогоняем операцию, сравниваем что в аудите. Тесты вида "вызываем аудит с параметрам" — это тесты "как написано"

·>Не "вызываем аудит с параметрам", а "послано такое-то сообщение в аудит".

Это непринципиально.

P>>Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь

·>Фреймворк-ориентед программинг? Нет, спасибо.

Это ж классика — отделяем логику, которая меняется часто, от той, которая меняется редко. По этому пути индустрия идет последние 50 лет примерно.
Re[23]: Что такое Dependency Rejection
Здравствуйте, ·, Вы писали:

P>>Моки изначально предназначались для тестов вида "вызываем вон то, вон так, в такой последовательности"

·>Может быть. Неясно какое это имеет значение сейчас, так исторические курьёзны. Даже если посмотреть на историю библиотек для тестов — за много лет много чего менялось и переделывалось.

И сейчас это основной кейс для моков. Вы и сами тащите "надо проверить old и new", и другого варианта не видите, как будто его нет. Можно же и дизайн поменять, что бы юнитами такое проверять. Но нет — вы топите за моки.

P>>·>Причём тут перемножают? Это диктуется требованиями. Если в json тебе нужен b64, а аналогичном месте protobuf тебе нужен Bytes, то хоть на bf пиши, у тебя будут комбинации.

P>>У вас — охотно верю.
·>Потому что у нас не хелловорды, а не как у вас, да?

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

P>>Я вам пример приводил, про время, вам он ожидаемо не понравился — язык не тот

·>Я не понял к чему ты скачешь с одного на другое. Обсуждали статью и MaitreD, потом crypto api, теперь вот ещё time api зачем-то...

Со статьё давно всё ясно. crypto api и time это пример, которые показывают, за счет можно отказаться от моков, и что будет, если этого не делать.

P>>·>Так в изначальном дизайне crypto так и было — создаём hmac нужного алгоритма, потом выводим в нужном представлении. Ты почему-то упаковал это в одну функцию и назвал успехом.

P>>В данном случае мне не надо переживать за поломаные тесты, если понадобится другой алгоритм, другая либа, итд.
P>>Вот понадобился не hmac а что другое — в файлике samples поменял десяток значений, и всё
·>Почему десяток? У тебя только десяток операций в api?

Это у вас на моках упадут все тесты всех операций апи. О том и речь. А на обычных юнит-тестах вы подкидываете новый набор значений, и всё путём.

P>>А ваша альтернатива этому — еще и тесты перебулшитить.

·>Один, скорее всего. Ибо одного теста достаточно чтобы зафиксировать логику вычисления hmac. В остальных тестах достаточно ассертить его наличие, но не конкретный формат.
"достаточно ассертить его наличие" — вот вам и привязка к "как написано"

Ага, тесты "как написано" Вам придется написать много больше, чем один тест — как минимум, пространство входов более-менее покрыть. Моками вы вспотеете это покрывать.

P>>Ну да, этож только у вас сложные системы.

·>Ну да, сам же сказал, что у тебя всё помещается в один файлик. Или он гиговый?

Вы там в телепатию заигрались? Что именно по вашему помещается в один файлик? Вся система, все тесты, вся система с тестами?
Вы чего то недопоняли, но вместо уточнения начинаете валять дурака?

·>Какой негатив? Вроде говорили об одном, теперь чего-то новое.

·>Вообще неясно причём тут time api и причём тут моки и тестирование вообще.

time api это пример дизайна, как можно уйти от комбинаторного взрыва.

P>>Успокойтесь — это все статически контролируется, только в вашу джаву такие фичи еще не завезли.

·>Спасибо, но сводить всё к массиву из 7 чиселок — это фигня полная и издевательство. Даже такое DateTimeOffset.from({...time.toFields, ...date.toFields(), offset: serverOffset}); — и всё поехало. И где наносекуды, интересно?

Где вы видите массив? Это объект, статически типизированый, наносекунды будут в time.toFields как fractionalSeconds. Вам телепатия еще не надоела?

·>Конструкторы удобнее и надёжнее с нужными типами, например, OffsetDateTime.of(date, time, offset), это хотя бы читабельно, и если что-то не так, не компиляется


Принципиальное отличе of вместо from

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

·>Это твои фантазии.

Вы сами пишите, что тестировать надо "как написано", это следует из того, как вы предлагаете решать задачу с hmac. Таких же задач будет не одна на проект, а целая куча. Вот и будут тесты "проверить что делает"

P>>Ну да — для вас перебулшитить тесты проблемой не является Еще и настаиваете, что так и надо.

·>Я настаиваю, что так не надо.

Если не надо, то должен быть другой подход к тестированию. А вы выбираете тесты на моках "проверим что вызывается hmac с нужными параметрами"

P>>Проходит же. Вот я и интересуюсь, кто настрочил горы непотребства

·>Вчерашние студенты?

Да не похоже.

P>>Эта разновидность тестов нужна и вам.

·>Нужны, но не для проверки каждой строчки кода, что параметры вызова не перепутаны. А только для тестирования интеграции.

АПИ и есть та самая интеграция.

P>>Продукт, система, приложение, апи, компонент, модуль. Для теста именно кода у нас другие инструменты — код-ревью, линт, дизайн-ревью, статические анализаторы, итд.

·>Я сказал "Они отменяют необходимость написания тучи этих самых xxxComposition, нет кода — нечего тестировать". Ты прикопаться решил к слову код? Ок, пусть будет не код, а модуль-компонент.
·>"Моки отменяют необходимость написания тучи этих самых xxxComposition, нет такого компонента|модуля — нечего тестировать." Так яснее?

Не отменяют. Когда вы укрупняете компонент, то тестировать его сложнее. Или ваше покрытие будет решетом, или вам придется понаписывать много моков вида "это вызывает то", которые сломаются даже при минорных изменения компоненты

P>>Можно. И это делается без моков. Если мы заложимся на значение или состояние, то получим куда больше гарантий.

·>Без моков ты предложил только полный запуск всей аппликухи, в лучшем случае с тестовой субд. Kafka/amps/lbm/solace/tibco/etc, кстати, тоже тестовую будешь пускать? Или как?

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

P>>В функции средний девелопер может понаделывать ошибок куда больше, чем перепутать old и new.

·>Я в этом и до среднего не дотягиваю, дохрена таких ошибок делаю, но вся эта фигня на раз ловится тестами, c моками (стабами), да.

Если вы написали тест на old и new, то конечно же словится. Только откуда следует, что это единственные проблемы?
Проблем может быть сколько угодно, именно конечный результат говорит что правильно а что нет
Иногда без контроля вызовов не получится — см. пример у буравчика, но и там можно уйти от самих моков за счет максимально дешовых стабов.

P>>Именно! А потому нам все контроллеры нужно тестировать в апи тестах — тем самым мы исключаем добрый десяток классов проблем.

·>И эти тесты дадут тебе гарантию?

Разумеется, мы ради этого и пишем тесты. Не только что бы убедиться, что работает здесь и сейчас, но что бы можно было перепроверить это в т.ч. на живом окружении.
После билда работает, после деплоя — нет, опаньки!
Впрочем, в прошлом году вы рассказывали, что деплой трогать низя — он у вас хрупкий, не дай бог повалится от лишнего запроса.

P>>Что вас смущает? deep.eq проверит всё, что надо. query это не строка, объект с конкретной структурой, чтото навроде

P>>
P>>{
P>>  sql: 'select * from users where id=?',
P>>  params: [id],
P>>  transformations: {
P>>     in: [fn1],
P>>     out: [fn2]
P>>  }
P>>}
P>>

·>Жуть. Ну ладно. Т.е. тут мы тестируем репозиторий и ассертим текст sql

Здесь мы тестируем построение запроса

·>Как проверить, что текст запроса хотя бы синтаксически корректен?


Для этого нам всё равно придется выполнить его на реальной бд. Расскажите, как вы решите задачу вашими моками.

> И что он при выполнении выдаст то, что ожидается?


А здесь как вы моками обойдетесь?

> И как ты собрался тут подменять субд? Ты обещал, что теперь эту хрень можно отдать любой db и оно выдаст одинаковый результат? Даже если эта субд это oracle или cassandra? Да там синтаксис банально другой.


А разве я говорил, что бд можно менять любую на любую? Построение запросов мы можем тестировать для тех бд, которые поддерживаются нами.

P>>Сами трансформации тестируются отдельно, обычными юнитами, например expect(fn1(user)).to.eq(user.id);

·>Так ведь надо трансформировать не некий user, а конкретно ResultSet возвращённый из "select *". Что колоночки в select местами не перепутаны, как минимум.

Что вас смущает? трансформация результата принимает ResultSet и возвращает вам нужный объект.

·>Ещё это всё "красиво" только на твоих хоумпейдж проектах. В реальном коде эти sql будут сотни строк с многоэтажными джойнами и подзапросами, и такие "тесты" станут даже немножечко вредить.


Расскажите, как вы это моками решите

P>>Вы все думаете в единицах старого дизайна, когда БЛ прибита гвоздями к бд.

·>Не к бд прибита. БЛ прибивается к репе.

Это одно и то же, и в этом проблема. Я ж вам говорю, как можно иначе — но вы упорно видите только вариант из 90х-00х
В новом подходе не надо БЛ прибивать ни к какой репе, ни к бд, ни к стораджу, ни к кафе, ни к внешним сервисам

P>>Шота я этого за 4 года не заметил

·>Может у тебя проекты написанные вайтишниками после курса ML, я не знаю. Но у тебя есть целый гитхаб, погляди насколько часто и для чего Object используют.

Я как раз с гитхаба и брал, если что.

P>>Юзеру так и скажете — мы не можем вернуть ваши деньги, потому что у нас в конфигурации возвраты отключены.

·>Для этого и есть L1 support — "проверьте, что ваш компьютер включен".

Я именно это сказал — L1 support так и скажет юзеру, "в конфиге отключено, значит неположено"

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

P>>Добавили, посмотрели дифом, вкомитали. Вам же не надо сразу всё обрабатывать.

·>А в дифе 10к строчек отличаются. И как это смотреть? Аудит же пишется для каждой операции, т.е. каждого теста, да ещё и не по разу.

А почему 10к а не 10к миллионов?

P>>Если апи возвращает то, что надо, это значит что у вас связка конфиг-di-sl-рантайм-переменные-итд склеено правильно.

·>И это ты предлагаешь гонять на каждый "updateUser(newUser, oldUser)"? Спасибо, не надо нам такого щастя.

Да, я в курсе, у вас есть L1 суппорт, который скажет клиенту, что возвраты не положены.
Это не шутка — мне так L1 однажды залепил
Неделя бодания и перекинули проблему наверх, только когда я сослался на федеральный закон
Признавайтесь, ваша идея?

P>>Можно. Это старый подход.

·>Ты говоришь как будто это что-то плохое. Это разумный подход. Делить не по тому, что сейчас у фаулеров в моде, а по конкретному осязаемому критерию, т.к. это напрямую выражается во времени запуска и требуемых ресурсов для тестирования.

В данном случае вам нужно писать больше кода в тестах, и они будут хрупкими. Другого вы с моками не получите. Потому и убирают зависимости из БЛ целиком, что бы легче было покрывать тестами

P>>Это новый подход, позволяет обходиться без моков-стабов итд и свести тестирование ключевых вещей к дешовым юнит-тестам

·>У тебя тривиальное updateUser(newUser, oldUser) не тестируется юнитами. Любая мелочёвка требует запуска всего, в лучшем случае с in-mem субд.

Ага, сидим да годами ждём результаты одного теста. Вам самому не смешно?

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

·>С такими же гарантиями можно и просто метод дёргать. Аннотации это только от плохого дизайна.

Ну вот подергали вы метод. А потом вас попросили отразить всё такое в сваггере каком, что бы другим было понятно. Гы-гы. Ищите строчки в коде.
А с аннотациями взял да и отрендерил манифест.

P>>В этом случае можно сделать аудит через тесты состояния. Прогоняем операцию, сравниваем что в аудите. Тесты вида "вызываем аудит с параметрам" — это тесты "как написано"

·>Не "вызываем аудит с параметрам", а "послано такое-то сообщение в аудит".

Это непринципиально.

P>>Вы же не проверяете, что джава выполняет циклы правильно? Так и здесь

·>Фреймворк-ориентед программинг? Нет, спасибо.

Это ж классика — отделяем логику, которая меняется часто, от той, которая меняется редко. По этому пути индустрия идет последние 50 лет примерно.