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

Сообщение Re[3]: Testing Without Mocks: A Pattern Language от 09.03.2024 14:13

Изменено 09.03.2024 14:15 ·

Re[3]: Testing Without Mocks: A Pattern Language
Здравствуйте, rosencrantz, Вы писали:

R>·>Это полный аналог чего какой-нибудь Mockito.mock(CommandLine.class) и сделает в Java. Но не требуется ничего сувать в прод-код, все эти configurable resonses ( аналогом будет when().thenReturn() ) и tracking делается в тестовом коде (verify/ArgumentCaptor).

R>Там во вступлении автор говорит, что when/thenReturn и verify/ArgumentCaptor гвоздями прибивают тесты к деталям реализации и нафиг они нужны такие тесты. Как я понимаю, простейшая иллюстрация:
R>1. Можно verify/ArgumentCaptor, что код вызвал PrintStream::printf(). Но так делать бестолково, потому что тестируется реализация, а не эффект. Тот же самый принт могли сделать через println() например. За всеми этими методами следить чтоли?
А там не был PrintStream. У него специальный тип CommandLine был введён с двумя методами, который и мокается, правда вставкой мусора в прод-код. Аргументация "не используйте моки" — хромает, уровня straw-man. Как он собирался в принципе делать nullables для jdk-класса PrintStream?!

R>2. Лучше: подсунуть в код PrintStream, который просто соберёт весь аутпут, и потом его проверить. Это хоть и лучше, но всё равно завязано на реализацию.

Ну verify/ArgumentCaptor ровно это и делает. Просто уже готовая либа, которая собирает аутпут и т.п. Вместо этого предложено запихать в прод код какой-то EventEmitter и "this._emitter.emit(OUTPUT_EVENT, text);" — вот эта грязь останется и в прод-коде! Притом довольно убогая: пример с броском исключения — рассказал.

R>3. Ещё лучше: на каждую логическую операцию вывода чего-то на консоль — записывать куда-то во внутренний лог сообщения типа "выведено приветствие", "выведен копирайт", "выведена ошибка 453". В тесте потом смотришь на этот лог и этим ограничиваешься.

А зачем? Логи это так, для дебага в основном, да и меняться могут. А самая главная беда — факт вывода в лог вовсе не означает что действие действительно совершено. надо именно ассертить реальные действия.

R>Что там стоит за каждым событием — то ли PrintStream::printf(), то ли PrintStream::println(), то ли вообще десяток write(), то ли оно вообще это звуком юзеру говорит — и пофигу, тест не меняется.

О PrintStream — там всё просто, это легковесный класс с Zero-Impact Instantiation, неясно зачем его вообще мокать (как Pauel зачем-то предлагал мокать hmac в начале беседы в соседней теме). И код с ним можно делать через то что там называют "Overlapping Sociable Tests".
Re[3]: Testing Without Mocks: A Pattern Language
Здравствуйте, rosencrantz, Вы писали:

R>·>Это полный аналог чего какой-нибудь Mockito.mock(CommandLine.class) и сделает в Java. Но не требуется ничего сувать в прод-код, все эти configurable resonses ( аналогом будет when().thenReturn() ) и tracking делается в тестовом коде (verify/ArgumentCaptor).

R>Там во вступлении автор говорит, что when/thenReturn и verify/ArgumentCaptor гвоздями прибивают тесты к деталям реализации
Ну альтеранивой предлагается, что "вызыван writeOutput(text)". Разница-то в чём?

R> и нафиг они нужны такие тесты. Как я понимаю, простейшая иллюстрация:

R>1. Можно verify/ArgumentCaptor, что код вызвал PrintStream::printf(). Но так делать бестолково, потому что тестируется реализация, а не эффект. Тот же самый принт могли сделать через println() например. За всеми этими методами следить чтоли?
А там не был PrintStream. У него специальный тип CommandLine был введён с двумя методами, который и мокается, правда вставкой мусора в прод-код. Аргументация "не используйте моки" — хромает, уровня straw-man. Как он собирался в принципе делать nullables для jdk-класса PrintStream?!

R>2. Лучше: подсунуть в код PrintStream, который просто соберёт весь аутпут, и потом его проверить. Это хоть и лучше, но всё равно завязано на реализацию.

Ну verify/ArgumentCaptor ровно это и делает. Просто уже готовая либа, которая собирает аутпут и т.п. Вместо этого предложено запихать в прод код какой-то EventEmitter и "this._emitter.emit(OUTPUT_EVENT, text);" — вот эта грязь останется и в прод-коде! Притом довольно убогая: пример с броском исключения — рассказал.

R>3. Ещё лучше: на каждую логическую операцию вывода чего-то на консоль — записывать куда-то во внутренний лог сообщения типа "выведено приветствие", "выведен копирайт", "выведена ошибка 453". В тесте потом смотришь на этот лог и этим ограничиваешься.

А зачем? Логи это так, для дебага в основном, да и меняться могут. А самая главная беда — факт вывода в лог вовсе не означает что действие действительно совершено. надо именно ассертить реальные действия.

R>Что там стоит за каждым событием — то ли PrintStream::printf(), то ли PrintStream::println(), то ли вообще десяток write(), то ли оно вообще это звуком юзеру говорит — и пофигу, тест не меняется.

О PrintStream — там всё просто, это легковесный класс с Zero-Impact Instantiation, неясно зачем его вообще мокать (как Pauel зачем-то предлагал мокать hmac в начале беседы в соседней теме). И код с ним можно делать через то что там называют "Overlapping Sociable Tests".