170 похожих чатов

Вот недавно вообще задумался, есть ооп, есть функциональный стиль, где

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

46 ответов

3 просмотра

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

у меня ФП и ООП прекрасно существуют совместно

Прям без переменных с функторами и монадами?

.sha- Автор вопроса

Да, например, я могу заинжектить приватный внутренний массив, в котором Colection хранит элементы Это решит проблему при тестировании Но сделает использование класса очень неудобным, т.к. пользователям вообще не нужны эти детали, где именно collection хранит свои элементы

зачем тут лишняя терминология? просто функции как значения и функции с методами

Ну это не ФП, дело не в терминологии. Просто ты используешь лямбда функции и все.

а можно заижектить не в самой коллекции, а в её потомке и использовать для тестирования его?

глянь на это https://github.com/Svoloch/etc-js и скажи это ФП или ООП

.sha- Автор вопроса

Тогда тест (вот эта часть с потомком и инжектом) зависит от внутренностей класса. С таким успехом я могу тупо взять и заассертить приватное поле

модифицируй именно класс коллекции чтобы он сам проверял что в нём поменялось

Похоже функциональный стиль но нехватает таких вещей как композиция функций, я бы рекомендовал в ФП стиле рамду https://ramdajs.com/docs/

композиция это then (если я правильно понимаю это понятие)

Если бы фп и ооп прекрасно существовали по отдельности, в джаве бы на было лямбд, а в c# linq и делегатов

.sha- Автор вопроса

Хм. Это как?

В JS уже есть оператор композиции функций — |>

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

на данном этапе предпочитаю избегать всего что за пределами шестого стандарта

.sha- Автор вопроса

Ну вот minimal case, с которым возникла проблема у меня class Collection { _items = []; push(item) { this._items.push(item); } } // test describe(‘Collection’, () => { it(’should push items’, () => { const collection = new Collection(); collection.push(‘something’); assert(); // assert what?? }) })

так это не js, я то думаю откуда такие странные проблемы

.sha- Автор вопроса

Да блин, сейчас исправлю на js, по привычке написал на ts

.sha- Автор вопроса

Исправил

да оно и в js скомпилит так же, приватные поля там и так будут видны (или я ошибаюсь?)

.sha- Автор вопроса

Да, будут видны приватные поля, если только стандарт не выставлен на ES-из-последних Но не суть, вопрос же не в этом )

если видны, то результат модификации можно проверить

.sha- Автор вопроса

Тесты должны тестировать публичный интерфейс, который предоставляет класс. например, любые изменения _items не должны ломать тесты, если публичное API остается нетронутым

проверяйте приватные поля класса через Reflect.get

.sha- Автор вопроса

Проблема не в том, что я не могу получить приватные поля, а в том, что это делать неправильно в юнит тестах

Ты ж наверное не просто так туда добавляешь items наверное как то можешь их читать? Вот и надо тестировать метод который читает, либо ты вызываешь какой то другой класс, тогда с помощью. spy тестируешь что вызванному методу передались нужные items

Это плохая идея, тестировать надо только публичный интерфейс

.sha- Автор вопроса

Да, я могу сделать collection.push(…); assert.deepEqual(collection.getAll()); Просто это уже не юнит тест — если что-то сломаем в getAll, то наш тест push упадет, хотя не должен. Но похоже, это единственный выход

Юнит в ООП это класс а не метод

.sha- Автор вопроса

Хммм, а вот это многое объясняет..! Если это действительно так, то я могу в юнитах спокойно использовать несколько методов и не стабить если один метод использует другие этого класса? А где можно почитать про эту концепцию

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

В контексте юнит тестов доступ к приватным полям класса это рефлексия, поэтому вполне нормально

.sha- Автор вопроса

Я просто в таких случаях: class Class { // … method() { this.anotherMethod1(); this.anotherMethod2(); } } Стабал anotherMethod1 и 2 при тестировании method. То есть этого делать не стоит?

Стабить надо только внешние зависимости а тестировать через публичный интерфейс

.sha- Автор вопроса

Я руководствовался тем, что юнит — один метод, поэтому стабал (изменения в anotherMethod не приводят к падению теста method)

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

.sha- Автор вопроса

А почему так тесты будут более хрупкими? Типа если поменяется реализация anotherMethod, а стаб останется старым, то тесты начнут падать?

Ну да надо поддерживать больше стабов и при каждом рефакторинге приватных методов рефакторить еще и тест

.sha- Автор вопроса

Нет, приватные я не стабаю, только публичные

А зачем стабить публичные если их и так можно проверить?

.sha- Автор вопроса

Ну типа следуя концепции юнит теста, что тестируем ровно 1 вещь Если юнит — метод, тогда при падении теста я со 100% увернностью могу сказать, что проблема в этом конкретном методе, и не затрагивает другие

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

.sha- Автор вопроса

Понял, спасибо огромное за советы ) А интересно, возможно ли (и стоит ли) сделать такой класс, как приведенный выше collection, immutable?

Ну это зависит от того какие требования к программе, не забывай что immutable сущности жрут значительно больше пямяти

Похожие вопросы

Обсуждают сегодня

я не магистр хаскеля, но разве не может лейзи тип конвертнуться в не-лейзи запросив вычисление содержимого прям при инициализации?
deadgnom32 λ madao
100
в сях есть множество как в питоне? для удаление дубликатов
Linus
25
читать файл максимально быстро? странный вопрос))
zamtmn
53
тоесть, указав return eax, сгенерируется никому ненужная инструкция mov eax,eax ?
Aiwan \ (•◡•) / _bot
24
How to create an OS in C? what to study?
Linus
18
а зачем этот вопрос для удаления из чата?
Mёdkinson Medvezhkin
63
Всем доброго вечера! Хочу поделиться своим злоключением с человеком, который, как оказалось сюда тоже скидывал свое резюме. Жаль, что я вашу группу не нашел раньше… человек ки...
Роман Ахмедзянов
4
а как бы вылезти из ИО, что то типа IO -> Ether или в какую сторону смотреть ? что то туплю
Fedor
9
Компания Elif ищет менеджера проектов, который будет заниматься поиском и ведением новых проектов. Прежде чем приступить к работе, вам нужно пройти наш недельный курс, где вы ...
Elif
5
Привет, кто может сделать юзербота с апи? Задачи: - создавать группы - создавать каналы - задавать для созданных каналов аватарку или эмоджи, имя группы - добавлять в группы...
Lencore
11
Карта сайта