Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Пустой виртуальный метод вместо интерфейса

1779  1 2 все
AlexNek патриот12.10.24 17:15
AlexNek
NEW 12.10.24 17:15 
в ответ alex445 12.10.24 08:19
Меня уже больше интересует, зачем делать интерфейсы для целей лишь тестирования

почему именно для тестирования? И не обязательно всё мОкать.

вот у меня например, есть имплементация в памяти для теста и на диске для работы.


#21 
Программист коренной житель13.10.24 15:24
NEW 13.10.24 15:24 
в ответ alex445 12.10.24 08:19
если мок-фреймворки и так вытащат все данные рефлексией или парсингом исходного кода.

мок-фреймворки этим не занимаются :)

#22 
MrSanders коренной житель13.10.24 16:36
NEW 13.10.24 16:36 
в ответ Программист 13.10.24 15:24

смотря что он под "вытаскивать данные" имеет в виду... Так-то рефлекшен в полный рост используют.

#23 
Программист коренной житель14.10.24 11:17
NEW 14.10.24 11:17 
в ответ MrSanders 13.10.24 16:36

Я не очень понимаю, зачем мок-фреймфоркам использовать рефлекшены :)


Впрочем, есть и такие фреймворки, которые умеют подменять буквально все (в том числе и статики)... но вот только их мало кто использует :D

#24 
MrSanders коренной житель14.10.24 11:43
NEW 14.10.24 11:43 
в ответ Программист 14.10.24 11:17
Я не очень понимаю, зачем мок-фреймфоркам использовать рефлекшены :)

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

В яве самое, пожалуй, частое применение: подменить значение приватного поля.

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


Впрочем, есть и такие фреймворки, которые умеют подменять буквально все (в том числе и статики)... но вот только их мало кто использует :D

Ну. насчёт мало. Пытаются постоянно. У меня уже рука устала линейкой по пальцам бить. Но иногда прям действительно приходится. Как подсунут тебе какую-то библиотеку, так чтобы замочить в ней доступ к какому-нибудь сервису или к БД приходится или конструктор или какой-то приватный метод подменять.

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

#25 
Программист коренной житель14.10.24 12:33
NEW 14.10.24 12:33 
в ответ MrSanders 14.10.24 11:43
Затем, чтобы можно было работать с неидеальным кодом.

Все самые популярные мок-фремворки не работают с кодом. На вход ты даешь интерфейс или какой-нибудь класс и преймворк "пишет" свои классы наследники. Идеальный там код или нет вообще никого не интересует.


В яве самое, пожалуй, частое применение: подменить значение приватного поля.

Наиболее популярные мок-фремворки этим не занимаются.


#26 
alex445 патриот14.10.24 12:34
NEW 14.10.24 12:34 
в ответ MrSanders 14.10.24 11:43
всё что о шарпе знал уже благополучно забыл
В яве

Щас Котлин у всех на слуху.

#27 
7495 коренной житель14.10.24 18:09
7495
NEW 14.10.24 18:09 
в ответ alex445 14.10.24 12:34
Щас Котлин у всех на слуху.


Ну какой ещё котлин, ява или тем более сишарп, это всё для древних стариков, молодёжь выбирает лучшее, Я сказал учить всем Solidity!


вот тут пример простейшего вендора, и интерфейс токена, заливаю холокост токен, но дергал смартконтракт не через функцию, а фаллбак.


в результате ханурик, вклинился, захватил мой смартконтракт, вывел бабосики! 999.999 холохосттокенов ещё остались висеть на балансе:


Вопросы и Ответы - Программируем калькулятор пособий для беженцев вместе.
#28 
MrSanders коренной житель15.10.24 08:26
15.10.24 08:26 
в ответ Программист 14.10.24 12:33
Все самые популярные мок-фремворки не работают с кодом.

Да ниможитбыть! Кого-то засосала трясина ИИ. Представил себя большой языковой моделью.

Ладно, раскрою мысль: "чтобы программист, мог с помощью этих фреймворков писать тесты для неидеального кода".

Наиболее популярные мок-фремворки этим не занимаются.

Ну, или у нас разные популярные мок фреймворки, или кто-то в мире ява как я в шарпе. Мокито популярный? Что делает аннотация @InjectMocks в его расширении для JUnit-а?

А уж что делает EasyMock с рефлексией, чтобы работать с bridge - методами...

#29 
Программист коренной житель15.10.24 11:19
NEW 15.10.24 11:19 
в ответ MrSanders 15.10.24 08:26
Ладно, раскрою мысль: "чтобы программист, мог с помощью этих фреймворков писать тесты для неидеального кода".

Всегда можно нашлепать нетестируемый код и потом говорить, что фреймворки плохи :)

Неидеальный код можно приближать к идеалу рефакторингом.


Ну, или у нас разные популярные мок фреймворки, или кто-то в мире ява как я в шарпе.

Я про мир явы вообще ничего не знаю. Знаю только, что Java существует улыб


Мокито популярный?

Судя по всему, это что-то для специальное для явы. Ну и судя по тому, что они умеют подменять статики, рефлекшенами они таки пользуются.


А уж что делает EasyMock с рефлексией, чтобы работать с bridge - методами...

EasyMock тоже что-то исключительно из мира явы. Кто такие bridge - методы я не в курсе.

#30 
MrSanders коренной житель15.10.24 14:36
NEW 15.10.24 14:36 
в ответ Программист 15.10.24 11:19
Всегда можно нашлепать нетестируемый код и потом говорить, что фреймворки плохи :)

Подмена понятий. Мы не о "хороший-плохой" а о "зачем мок-фреймворку использовать reflection".

Неидеальный код можно приближать к идеалу рефакторингом.

Не всегда. Ну и пока не приблизили, что, не тестируем?

#31 
Программист коренной житель15.10.24 17:44
NEW 15.10.24 17:44 
в ответ MrSanders 15.10.24 14:36
Мы не о "хороший-плохой" а о "зачем мок-фреймворку использовать reflection".

Задача мок-фремворка - подменить внешние зависимости у unit under test.

Т.е. для того, чтобы код был тестируемым, нужно фактически 2 вещи: 1) unit under test должен зависить от абстракций и 2) нужно иметь возможность инжектить эти абстракции (самое простое - через конструктор).


Если эти 2 условия соблюдаются, то никакие рефлекшены мок-фреймвокру не нужны :)


Ну и пока не приблизили, что, не тестируем?

Пока не приблизили, это все легаси, которое и так работает. Покрывать тестами легаси можно, но вот насколько это эффективно - большой вопрос.

Если же у вас новый код нетестируемый, то либо вы сами себе злобные Буратины, либо тесты вам нахрен не нужны.

#32 
alex445 патриот15.10.24 19:18
NEW 15.10.24 19:18 
в ответ Программист 15.10.24 17:44
тесты вам нахрен не нужны.

Разве так можно? Это же тяжкий грех!

#33 
MrSanders коренной житель15.10.24 20:41
NEW 15.10.24 20:41 
в ответ Программист 15.10.24 17:44, Последний раз изменено 15.10.24 21:00 (MrSanders)
Если эти 2 условия соблюдаются, то никакие рефлекшены мок-фреймвокру не нужны :)

Угу. А рядом порхают единороги и попукивают радугой феи. Вот только есть ещё одна загвоздка - юнит у нас не класс. Юнит у нас - метод. И для тестирования метода приходится мочить другие методы того же самого класса. Или суперкласса. А вот они могут быть из другого фреймворка. И с ними и случаются засады.

// Customer - наш класс. А Entity - класс фреймворка, которому 5 лет, от другой фирмы, от которого у нас нет исходников.
// Да даже если б и были, модифицировать его мы не можем. 
public class Customer extends Entity {
  private final String firstName;
  ....
  private String plz;
  public boolean isSame(Person other) {   
    // Тут логика, которую мы хотим протестировать
    if(other == null) return false;
    // а вот тут порылась собака. Метод getPrimaryKey() определён в Entity. Из чужого фреймворка. И он финальный.
    // т.е. его переписать нельзя. Он просто возвращает primary key с которым этот объект сохранён в БД. Или -1 если
    // ещё не сохранён. А сеттера к нему нет. Или скрыт. Бывает, да? Ели это тот же объект из БД то он "тот же самый".
    if(getPrimaryKey() == other.getPrimaryKey()) return true;
    // и дальше код, который надо тестировать.
    boolean result = getName().equals(other.getName() && ....;
    result &= //ещё что-нибудь.  
    return result;
  } 
}

Ну и как же мне сделать этот код тестируемым по феншую? Написать свою public long getPkFromEntity() { return getPrimaryKey();} ?

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

А может лучше воспользоваться рефлексией и подставить в приватное поле other.primaryKey (унаследованное от суперкласса Entity) значение 123?


Пока не приблизили, это все легаси, которое и так работает.

Эту реплику из зала мы, товарищи, сейчас отметём с негодованием. Как неорганизованную. (ц)

Не верно. Это не наше легаси. И не его мы тестируем. Мы его должны использовать. Иначе ORM работать не будет. А тестировать мы должны свой код. Который от легаси зависит.


И таких примеров не один и не 10. Иногда бывают сильносвязанные классы. Ну вот надо чтобы А знало Б, а Б знало А. Цикл. И уже никто не может передать А или Б в конструктор. Делаем завод, который пару А и Б сгенерирует, конструкторы и сеттеры прячем чтобы только завод их вызвать мог, геттеры финальные (не переписываемые) опять же всё по феншую. А вот красота с "инжектить абстракции" в тесте поломалась.


А бывают DI фреймворки, которые ТРЕБУЮТ чтобы конструктор был пустым. А все зависимости засовывают напрямую в аннотированные поля. Приватные. И наш красивый код ДОЛЖЕН использовать этот фреймворк. Потому что экосистема. И именно потому что экосистема к коду архитектурное требование - сеттеров быть не должно (мнэ, на вашем языке - проперть ридонли :)). Потому что значения установит DI. А геттеры или финальные (не переписываемые) или их нет, чтобы не давать доступа к полю даже наследникам.

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


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


P.S. Кстати, примерно такой и была первая версия EasyMock-а. Только интерфейсы мочить умела. Но автор быстро понял что этого для реальной жизни не хватает.

#34 
alex445 патриот15.10.24 23:26
NEW 15.10.24 23:26 
в ответ MrSanders 15.10.24 20:41, Последний раз изменено 15.10.24 23:29 (alex445)
А бывают DI фреймворки, которые ТРЕБУЮТ чтобы конструктор был пустым. А все зависимости засовывают напрямую в аннотированные поля. Приватные. И наш красивый код ДОЛЖЕН использовать этот фреймворк. Потому что экосистема. И именно потому что экосистема к коду архитектурное требование - сеттеров быть не должно (мнэ, на вашем языке - проперть ридонли :)). Потому что значения установит DI. А геттеры или финальные (не переписываемые) или их нет, чтобы не давать доступа к полю даже наследникам.

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

#35 
Программист коренной житель16.10.24 08:40
NEW 16.10.24 08:40 
в ответ MrSanders 15.10.24 20:41
Вот только есть ещё одна загвоздка - юнит у нас не класс. Юнит у нас - метод.

Да хоть кого выбери юнитом. Юнит в любом случае должен работать с абстракциями.


Ну и как же мне сделать этот код тестируемым по феншую?

Очень просто - использовать абстракции. Если их нет, то ввести :) Использовать "тонкие" DTO,

Можно также использовать прокси-объекты.

Было бы желание сделать по феншую :)


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

Ну это зависит от того, как расширять :) Совсем необязательно, что будет менее читаемым.


А может лучше воспользоваться рефлексией и подставить в приватное поле other.primaryKey (унаследованное от суперкласса Entity) значение 123?

Угу, а еще тебе понадобится реальная БД, т.к. где-нибудь в этом Entity погребено подключение к БД. Надо будет держать эту БД в валидном для теста состоянии. А еще не дай бог кому-то придет в голову поменять логику Entity и приватное в лучшем случае удалят, а в худшем - будут использовать как-то иначе. Или натрафят обфускатор :)


А бывают DI фреймворки, которые ТРЕБУЮТ чтобы конструктор был пустым.

Ну во времена, когда один класс может имень много конструкторов это вообще самая маленькая проблема в мире :)


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

Да пофиг :) Переходи на уровень абстракций, т.е. интерфейсов. На этом уровне совершенно наплевать на всякие там финальные или приватные методы/проперти... их просто нет, т.к. интерфейс по определению публичный :)


И угадай с трёх раз, что же обычно выбирают?

Стреляющие себе в ногу выбирают рефлекшены :) Это ж очевидно :D :D :D

#36 
MrSanders коренной житель16.10.24 20:50
NEW 16.10.24 20:50 
в ответ Программист 16.10.24 08:40
Да пофиг :) Переходи на уровень абстракций, т.е. интерфейсов.

Феерично. Мышки, станьте ёжиками. Какой, блин, интерфейс, если у нас требование наследовать от Enttity?

Ладно, не буду отрывать от радужных феечек, пока сам не увидишь - не поймёшь.

#37 
1 2 все