• Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Дмитрий, Так мне и нужно только тип проверить и параметры в конструкторе, но когда я передаю любой url, а передачу url мне нужно проверить тоже, то при создании объекта он сразу лезет на этот url и выкидывает exception если не получается!
  • Как реализовать модульный тест метода содержащего создание экземпляра SoapClient?

    @HiDiv Автор вопроса
    Я уже писал выше, что я хочу проверить (именно на этапе unit-тестирования), что
    • На выходе метода getSoapClient действительно объект класса SoapClient.
    • Аргумент $url, переданный на вход getSoapClient был использован в качестве url при вызове конструктора SoapClient.
    • При вызове конструктора SoapClient были использованы именно те параметры, которые были захардкодены в методе getSoapClient.

    Интеграционные и другие высокоуровневые тесты это конечно хорошо, но эти утверждения вполне можно и нужно (IMHO) проверить на этапе unit-тестирования. Эти требования достаточно "формальны" для этого, но проверка соблюдения их довольно важный этап тестирования... Поправьте меня если это не так.
  • Как правильно покрыть тестами приведенный в примере код?

    @HiDiv Автор вопроса
    index0h,
    В том то и дело, мокать тестируемый класс - это не самая лучшая практика, да иногда приходится, но лучше стараться этого не делать. Дело в том, что мок метода вносит, помимо заданного поведения еще и источник ошибок. Приведу пример допустим вы замокали getSql, тесты методов, использующие этот мок сработают корректно. Вы даже покроете неспосредствнно getSql и проверите, что он возвращает правильную sql-ину. Пройдет время и вы измените getSql упадет только тест, проверяющий getSql, остальные - нет.

    Так в том-то и дело, что по моей практике лучшие показатели (в плане гарантии работоспособности) дают "интеграционные тесты", когда для каждого теста прям в БД "формируется среда" для конкретного "пограничного состояния", на вход метода подаем "определенное значение" и просто сравниваем результат с ожидаемым. В этом случае используются/проверяются все методы, включая private/protected, явно проверяется синтаксис "сгеренированного" sql-запроса и его "логическая" правильность. Но это не модульные тесты и времени выполнения они требуют значительно больше! Также их поломка с ходу говорит лишь о наличии проблемы, но не о месте ее возникновения (слишком много кода задействовано в процессе).

    С другой стороны есть отрицательный опыт, когда я полностью покрыл код модульными тестами (каждый метод в отдельности), но после выкатки на стейдж сразу все развалилось! Оказалось, что в одном из sql-запросе была синтаксическая ошибка (не верно указано имя поля) и все эти автотесты оказались полностью бесполезны!

    Сейчас пытаюсь балансировать между двумя крайностями. С одной стороны пишу модульные тесты, которые тестируют чисто "код в вакууме". С другой интеграционные, которые значительно дольше выполняются, но проверяют ВСЕ пограничные случаи. Но это очень много работы! Реально получается, что время на разработку автотестов приближается (если не больше) к времени разработки самого функционала... Это неприемлемо для большинства коммерческих проектов!
  • Как правильно покрыть тестами приведенный в примере код?

    @HiDiv Автор вопроса
    Спасибо за ссылку на документ, с большим интересом прочитал, но, насколько я понимаю, это "видение отдельной группой лиц". Есть и другие источники, которые заслуживают доверия, например, книги Роберта Мартина и С. Макконнелла про чистый/совершенный код... Там, кстати, уделяется большое внимание структуре методов и их размеру, да и принципов SOLID стоит придерживаться...

    Правда, обычно я не разделяю getSql и getSqlParams, а делаю все вместе в getCompleteSql. В остальном, с учетом потребности в моках, данное разделение мне не кажется избыточным.

    Ну, а с предложением засунуть все в getValue я точно не соглашусь. Это точно не даст никакого профита! Во первых, в "одну кашу" смешаем "мух" и "котлеты". А, во вторых, упрощения тестирования в этом я тоже не вижу.

    2. Инстансы db и timedate стоит передавать в конструктор явно, а от статики отказываться, на сколько это возможно.

    Тут я скорее согласен, но дело в том, что приведенный пример это часть бОльшого "фреймворма" и там принят определенный шаблон для реализации расширений, который выглядит похоже предложенному мной варианту. $db и $timedate на самом деле это вообще глобальные переменые-синглетроны и только в последнее время стали рекомендовать использовать getInstance, чтобы не зависеть от них.

    Ну, а передавать их каждый раз в конструктор параметрами, зная все это как-то не очень... Другое дело, что можно сделать их необязательными параметрами и оставить их автозаполнение из инстансов, если не указали. Тогда с "основном коде", можно их (параметры) всегда опускать, а в тесте передать через них моки...

    Однако, все это никак не отвечает на мои основные вопросы по тестированию... ;(
  • Как правильно покрыть тестами приведенный в примере код?

    @HiDiv Автор вопроса
    Большое спасибо за ссылку. Посмотрел ролик со всем вниманием, но, к сожалению, вопросов от этого не убавилось...

    Я уже писал в самом начале, что меня не нужно "агитировать за красных", я прекрасно понимаю нужность и полезность автотестов. Если отбросить эти моменты, то от ролика останется 1/3.

    С тезисом, что нужно разбивать код на более мелкие самостоятельные "фрагменты" полностью согласен, но в моем примере это и так уже реализовано. Если не согласны, то покажите, что еще можно улучшить.

    По поводу отказа от приватных методов, тут вообще "абзац". С этим категорически не согласен! Есть механизмы чтобы тестировать и их, не в этом вопрос. Я спрашиваю, как "идеологически правильно" это стоит делать?

    По поводу работы с БД, тоже не сказано ничего нового. Если в тесте sql-запросов, которые приводятся в ролике, будет "синтаксическая ошибка" или запрос не будет соответствовать текущему состоянию БД, то все тесты будут прекрасно проходить (там же куча копипаста), но на проде все взорвется!

    Я прекрасно понимаю, что проверку взаимодействия с БД можно отнести к отдельным, "высокоуровневым" тестам... Вопрос, как такие тесты реализовать, это во первых? А, во вторых, суть самой задачи "правильно вытащить из БД нужные данные"! Никто не просит проверять выполняется ли вообще подключение к БД!
  • Почему ESlint не понимает тип свойств наследуемых из родительского класса?

    @HiDiv Автор вопроса
    Кажется я нашел истинную причину! Если поместить базовый класс в обычный файл с расширением .ts, то все описанные выше ошибки ESlint уходят... Дело в том, что проект делается на vuejs и код находится в файлах-компонентов с расширением .vue в секции
  • Почему ESlint не понимает тип свойств наследуемых из родительского класса?

    @HiDiv Автор вопроса
    Василий Банников, Добавил в вопрос. Сам пример вымышленный, т.к. это часть большого проекта... Не могу же я его сюда весь закопипастить.

    Но суть остается
  • Почему ESlint не понимает тип свойств наследуемых из родительского класса?

    @HiDiv Автор вопроса
    Uneasy Hearts Weigh the Most, Если написать так, то линтер пишет, что и так понятно, что string
    class Base {
      label: string = 'Лейбл'
      getLabel() {
        return 'Это ' + this.label
      }
    }
  • Как динамически зарегистрировать локально новый компонент vue?

    @HiDiv Автор вопроса
    Я понимаю, что должно. Более того, оно большую часть времени работает, но периодически (мы так и не смогли точно поймать момент) работать перестает. Есть подозрения, что это как-то связано с тем, заходим ли мы на компонент-страницу, которая содержим эти компоненты сразу (через url) или через навигацию приложения и делаем ли мы обновление страницы с hard reset браузера.

    Получается, что глобальная регистрация компонентов выполняется в асинхронной функции (action vuex) через глобальную же Vue, не видна в this.$options.components компонента-страницы. Это видно через тестовую печать в console.log.

    Пока сделал такое решение
    registerComponents(fieldTypes: string[]) {
        console.log('Вошли в регистрацию', fieldTypes)
        fieldTypes.forEach(type => {
          const compName = getComponentNameForField('Lv', type)
          if (typeof this.$options.components[compName] === 'undefined') {
            console.log('Регистрируем '+ compName)
            this.$options.components[compName] = () => import('components/fields/' + type + '/' + compName + '.vue')
          } else {
            console.log('Уже есть '+ compName)
          }
        })
      }

    Оно конечно не соответствует документации, но пока при тестировании ошибок больше нет...
  • Как динамически зарегистрировать локально новый компонент vue?

    @HiDiv Автор вопроса
    Если честно, то не понял, как ваш пример может быть ответом на мой вопрос.
    Забыл уточнить вначале, разговор про 2-ю версию vuejs.

    Я знаю, что компоненты это обычные объекты, но еще раз повторюсь. Сами компоненты расположены в отдельном каталоге в виде файлов с vue расширением. На этапе сборки приложения я не знаю, какие из них понадобятся в процессе выполнения. Явно перечислять их все, даже через () => input(), я не хочу. Новые компоненты в runtime должны добавляться и регистрироваться по потребности.
  • Почему при выполнении вложенных операций теряется тип переменной?

    @HiDiv Автор вопроса
    Lynn «Кофеман», с этим я соглашусь и это понятно, как решить, но вопрос-то совершенно в другом.
    Почему выдается ошибка/предупреждение ESLint на columnDef.fieldName === selectedColumn.fieldName
  • Почему при выполнении вложенных операций теряется тип переменной?

    @HiDiv Автор вопроса
    Aetae, повторил

    Только тут ошибки не показывает. На самом деле у меня ошибку показывает ESLint: Unsafe member access .fieldName on an `any` value.(@typescript-eslint/no-unsafe-member-access) и т.п.
  • Как реализовать обновление объекта на основании маппинга полей?

    @HiDiv Автор вопроса
    Aetae, мне кажется, что const k = toKey as keyof typeof dest
    можно не делать, а использовать и дальше toKey as keyof typeof dest
    В остальном все здорово.
  • Как реализовать обновление объекта на основании маппинга полей?

    @HiDiv Автор вопроса
    Я про вариант с let тоже подумал, но "внизу" все же js, т.ч. тут правильнее const...
    А так получается, что в угоду ts мы намеренно объявляем переменную вне необходимой области видимости.