Рубрики
Без рубрики

Введение в развитие тестирования с Vue.js

Сарой Дайэн введение в развитие, ориентированное на тестирование с Vue.jsphoto by Louis Reed на Unsplashtest-ориентированное развитие (TDD) – это процесс, в котором вы пишете тесты, прежде чем писать связанный код. Сначала вы пишете тест, который описывает ожидаемое поведение, и вы запускаете его, обеспечивая выгоду. Затем вы

Автор оригинала: FreeCodeCamp Community Member.

Сарха Дайн

Разработка тестирования (TDD) – это процесс, где Вы пишете тесты, прежде чем написать связанный код Отказ Сначала вы пишете тест, который описывает ожидаемое поведение, и вы запускаете его, обеспечивая выгоду. Затем вы пишете самый глупый, самый простой код, который вы можете сделать тестовый проход. Наконец, вы решаете код, чтобы сделать это правильно. И вы повторите все шаги для каждого теста, пока не закончите.

Этот подход имеет много преимуществ. Во-первых, Это заставляет вас думать, прежде чем код Отказ Очевидно, чтобы спешить в написании кода, прежде чем установить, что он должен сделать. Эта практика приводит к трастам времени и написания сложного кода. С помощью TDD любой новый кусок кода требует первого теста, поэтому у вас нет выбора, но не найдите время, чтобы определить, что этот код должен делать, прежде чем писать его.

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

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

Почему TDD для компонентов?

Тестирование компонента может быть противоборбительным Отказ Как мы видели в Устройство тестирует ваш первый компонент Vue.js , требует ментального сдвига, чтобы обернуть голову вокруг тестирования компонентов по сравнению с тестированием простых сценариев, зная, что тестировать, и понимание линии между модульными тестами и концом к концу.

TDD делает все это проще Отказ Вместо того, чтобы написать тесты, изучав все биты и куски готового проекта и пытаетесь угадать, что вы должны покрыть, вы делаете обратное. Вы начинаете с фактических спецификаций, список вещей, которые должны быть компонентом сделать , не заботясь о том, как это делает. Таким образом, вы гарантируете, что все, что вы тестируете, является общедоступным API, но вы также гарантируете, что вы ничего не забуду.

В этом руководстве мы построим Пикера цвета Отказ Для каждого Swatch пользователи могут получить доступ к соответствующему цветовому коду, либо в шестнадцатеричном, RGB или HSL.

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

В этой статье мы будем глубоко погружаться в TDD. Мы будем Поместите некоторые спецификации вместе Прежде чем написать одну строку кода. Тогда мы будем Испытайте каждую публичную функцию в тестовой моде. Наконец, мы будем размышлять о том, что мы сделали, и Посмотрите, что мы можем извлечь из этого Отказ

Прежде чем начать

Это руководство предполагает, что вы уже построили что-то с Vue.js до, и письменные модульные тесты для него используют Vue Test Utils и Jest (или аналогичный тестовый бегун). Он не будет глубже в основные основы, поэтому убедитесь, что вы встаете на скорость сначала. Если вы еще не там, я рекомендую вам перейти Создайте свой первый компонент Vue.js и Устройство тестирует ваш первый компонент Vue.js Отказ

TL; DR: Этот пост уходит глубоко в том, как и почему. Он предназначен для того, чтобы помочь вам понять каждое решение за тестированием компонента Real-World Vue.js с TDD и научить ваших проектных решений для ваших будущих проектов. Если вы хотите понять весь процесс мысли, читайте дальше. В противном случае вы можете пойти прямо к Последствия В конце или посмотрите на окончательный код на Github Отказ

Запишите ваши спецификации

Прежде чем даже писать свой первый тест, Вы должны записать обзор того, что должен делать компонент Отказ Наличие спецификации делает тестирование намного простым, поскольку вы в основном переписываете каждый спектр в виде тестов.

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

Во-первых, у нас есть коллекция Образцы цвета Отказ Мы хотим иметь возможность пройти список пользовательских цветов и отображать в качестве образцов в компоненте. Первый должен быть выбран по умолчанию, и конечный пользователь может выбрать новый, нажав на него.

Во-вторых, у нас есть Цветной режим Togger Отказ Конечный пользователь должен иметь возможность переключаться между тремя режимами: шестнадцатеричные (по умолчанию), RGB и HSL.

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

Как видите, мы не слишком глубоко в деталях; Мы не указываем, что должны быть этикетки цветового режима, или что выглядит активное состояние для образцов цвета. Мы можем использовать большую часть небольших решений на лету, даже при выполнении TDD. Тем не менее, мы пришли Из простого определения того, что должен быть компонент, чтобы всеобъемлющий набор спецификаций для начала Отказ

Написать тестовый код

Во-первых, вам нужно создать новый проект Vue с Vue Cli Отказ Вы можете проверить Создайте свой первый компонент Vue.js Если вам нужен пошаговый руководство.

Во время процесса лесных лесов вручную выберите функции и убедитесь, что вы проверяете Устройство тестирования Отказ Выберите Jest как ваше решение для тестирования и продолжите, пока проект не установлен, зависимости не установлены, и вы готовы к работе.

Нам нужно использовать файлы SVG в качестве компонентов, поэтому вам также необходимо установить нужный загрузчик для них. Установить Vue-SVG-погрузчик как зависимость Dev, и добавьте правило для него в вашем vue.config.js файл.

// vue.config.js

module.exports = {
  chainWebpack: config => {
    const svgRule = config.module.rule('svg')
    svgRule.uses.clear()
    svgRule.use('vue-svg-loader').loader('vue-svg-loader')
  }
}

Этот погрузчик не работает хорошо с шумом по умолчанию, что вызывает тесты для броска. Чтобы исправить это, создать svgtransform.js Файл Как задокументировано на сайте и редактируйте свой jest.config.js следующим образом:

// svgTransform.js

const vueJest = require('vue-jest/lib/template-compiler')

module.exports = {
  process(content) {
    const { render } = vueJest({
      content,
      attrs: {
        functional: false
      }
    })
    
    return `module.exports = { render: ${render} }`
  }
}

// jest.config.js

module.exports = {
  // ...
  transform: {
    // ...
    '.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
    '^.+\\.svg$': '/svgTransform.js'
  },
  // ...
}

Обратите внимание, что мы удалили «SVG» из первого регулярного выражения (тот, который преобразуется с помощью jest-преобразования ). Таким образом, мы гарантируем, что SVGS забрать svgtransform.js Отказ

Кроме того, вам нужно установить Color-Convert как зависимость. Нам понадобится как в нашем коде, так и в наших тестах.

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

Вместо этого откройте свой проект и создайте новый ColorPicker.Vue Одно файловый компонент в SRC/Компоненты/ каталог. В Тесты/блок/ Создайте его связанный файл SPEC.









// ColorPicker.spec.js

import { shallowMount } from '@vue/test-utils'
import ColorPicker from '@/components/ColorPicker'

describe('ColorPicker', () => {
  // let's do this!
})

В вашем терминале выполните следующую команду для запуска тестов:

npm run test:unit --watchAll

На данный момент вы должны получить ошибку, потому что у вас еще нет тестов. Не волнуйтесь, хотя; Мы исправим это в ближайшее время? Обратите внимание на использование – -Watchall Флаг в команде: jest теперь смотрит ваши файлы. Таким образом, вам не придется перезапустить тест вручную.

TDD идет на 3 этапа:

  1. Красный : Вы пишете тест, который описывает ожидаемое поведение, то вы запускаете его, убедившись, что он не удается.
  2. Зеленый : Вы пишете самый глупый, самый простой код, который вы можете сделать тестовый пропуск.
  3. Рефакторист : Вы рефикторуете код, чтобы сделать это правильно.

Шаг 1: красный

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

Во-первых, мы хотим убедиться, что компонент отображает каждый цвет, который мы предоставляем как отдельный образ. Мы бы пропустили те, как реквизиты, в виде массива шестнадцатеричных строк. В компоненте мы будем отображать список как неупорядоченного списка, и назначьте цвет фона через Стиль атрибут.

import { shallowMount } from '@vue/test-utils'
import ColorPicker from '@/components/ColorPicker'
import convert from 'color-convert'

let wrapper = null

const propsData = {
  swatches: ['e3342f', '3490dc', 'f6993f', '38c172', 'fff']
}

beforeEach(() => (wrapper = shallowMount(ColorPicker, { propsData })))
afterEach(() => wrapper.destroy())

describe('ColorPicker', () => {
  describe('Swatches', () => {
    test('displays each color as an individual swatch', () => {
      const swatches = wrapper.findAll('.swatch')
      propsData.swatches.forEach((swatch, index) => {
        expect(swatches.at(index).attributes().style).toBe(
          `background: rgb(${convert.hex.rgb(swatch).join(', ')})`
        )
      })
    })
  })
})

Мы смонтировали наши ColorPicker Компонент и написал тест, который ожидает найти элементы с помощью фонового цвета, соответствующие цвета, которые передаются в виде опоры. Этот тест обязан потерпеть неудачу : У нас в настоящее время нет ничего в ColorPicker.Vue Отказ Если вы посмотрите на свой терминал, вы должны ошибаться, говоря, что ни один элемент не существует на 0. Это здорово! Мы только что прошли первый шаг TDD с летающими цветами.

Шаг 2: зеленый

Наш тест не может; Мы на правильном пути. Теперь, время, чтобы сделать это прохождение. Нам нежно заинтересованы в письменном видении или Smart Code в этот момент, все, что мы хотим, это сделать шутку счастливой. Прямо сейчас Vue Test Utils жалуется на то, что у нас нет события не имеют элемента по индексу 0.

[vue-test-utils]: no item exists at 0

Самое простое, что мы можем сделать, чтобы сделать эту ошибку уходить, – это добавить неупорядоченный список с помощью Swatch Класс на элементе списка.

Jest все еще жалуется, но ошибка изменилась:

Expected value to equal:
  "background: rgb(227, 52, 47);"
Received:
  undefined

Это имеет смысл; Пункт списка не имеет Стиль атрибут. Самая простая вещь, которую мы можем сделать с этим, – это жесткий код Стиль атрибут. Это не то, что мы хотим в конце, но мы еще не обеспокоены этим. Что мы хотим, это Для нашего теста на зеленый Отказ

Поэтому мы можем, следовательно, Hardcode пять элементов списка с ожидаемыми атрибутами стиля:

Тест должен пройти.

Шаг 3: Refactor

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



Когда тесты регины, они все равно должны пройти? Это значит W E Успешно восстановил код, не влияя на вывод. Поздравляем, вы только что завершили свой первый цикл TDD!

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

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

Это вся идея развития тестирования: мы не пишем код, чтобы делать вещи, Мы пишем код, чтобы пройти тесты Отказ Реверсив отношения, мы обеспечиваем надежные испытания с фокусом на результате.

Что мы тестируем?

Другой вопрос, который может прийти к уму, это Как мы принимаем решение, что тестировать Отказ В Устройство тестирует ваш первый компонент Vue.js Мы видели, что мы должны тестировать только общедоступные API нашего компонента, а не внутреннее реализацию. Строго говоря, это означает, что мы должны покрывать взаимодействия пользователя и реквизит меняется Отказ

Но это все? Например, это нормально для вывода HTML, чтобы сломаться? Или для имена классов CSS для изменения? Мы уверены, что никто не полагается на них? Что ты не сам?

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

Например, если вы создаете эту цветную панель как компонент с открытым исходным кодом, ваши пользователи являются другими разработчиками, которые используют его в своих собственных проектах. Они, вероятно, полагаются на имена классов, которые вы предоставляете стилю компонента по своему вкусу. Имена классов становятся частью вашего общедоступного API, потому что ваши пользователи полагаются на них.

В нашем случае мы не обязательно будем делать компонент с открытым исходным кодом, но у нас есть просмотр логики, которая зависит от конкретных названий классов. Например, для активных образцов важно иметь Активный Название класса, потому что мы полагаемся на него, чтобы отобразить галочку, в CSS. Если кто-то изменит это случайно, мы хотим узнать об этом.

Испытательные сценарии для компонентов пользовательского интерфейса высоко зависят от случая использования и ожиданий. В зависимости от того, что вам нужно спросить себя Я забочусь об этом, если это меняет ?

Следующие тесты

Тестирование образцов

Давайте перейдем к следующему тесту. Мы ожидаем, что первый образец списка будет той, который выбран по умолчанию. Снаружи, Это то, что мы хотим убедиться, что продолжает работать так же Отказ Пользователи могут, например, полагаться на имя активного класса для стиля компонента.

test('sets the first swatch as the selected one by default', () => {
  const firstSwatch = wrapper.find('.swatch')
  expect(firstSwatch.classes()).toContain('active')
})

Этот тест тоже должен потерпеть неудачу, так как элементы списка в настоящее время нет никаких классов. Мы можем легко сделать этот проход, добавив класс в элементе первого списка.

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

    
    
    export default {
      // ...
      data() {
        return {
          activeSwatch: 0
        }
      }
    }

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

    test('makes the swatch active when clicked', () => {
      const targetSwatch = wrapper.findAll('.swatch').at(2)
      targetSwatch.trigger('click')
      expect(targetSwatch.classes()).toContain('active')
    })

    На данный момент ничего не происходит, когда мы нажимаем по образцу. Однако благодаря нашему предыдущему рефактору мы можем сделать этот тест Gree Green и даже пропустить шаг рефакторов.

  • Этот код делает тестовый проход и даже не нужен рефактором. Это повезло побочный эффект выполнения TDD Иногда процесс приводит к тому, что либо писать новые тесты, которые либо не нужны рефакторы, либо даже которые сразу проходят.

    Активные образцы должны показать галочку. Мы добавим его сейчас без написания теста Вместо этого мы будем контролировать их видимость через CSS позже. Это хорошо, так как мы уже проверили, как Активный класс применяется.

    Сначала создайте Checkmark.svg Файл в SRC/Активы/ Отказ

    
      
    

    Затем импортируйте его в компонент.

    import CheckIcon from '@/assets/check.svg'
    
    export default {
      // ...
      components: { CheckIcon }
    }

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

  • Хорошо! Теперь мы можем перейти к следующему элементу нашего компонента: Цветной режим Отказ

    Тестирование цветового режима

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

    Вместо тестирования кнопки этикетки, Мы полагаемся на названия классов Отказ Это делает наш тест более надежным, так как мы можем легко определить имя класса как часть договора нашего компонента. Однако ярлыки кнопок должны быть в состоянии изменить.

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

    Одно решение может быть доступен для доступа к данным компонента для динамическими модами. Vue Test Utils позволяет нам сделать это через VM Собственность, но опять же, это тесно пары наш тест со внутренней реализацией режимов. Если завтра мы решили изменить способ, которым мы определяем режимы, тест сломался бы.

    Другое решение – продолжать движение с черным ящиком и ожидать, что имя класса соответствует данному шаблон Отказ Нам все равно, что это Color-Mode-Hex , Color-Mode-HSL или Color-Mode-Xyz Пока похож на то, что мы ожидаем снаружи. Jest позволяет нам сделать это с регулярными выражениями выражения.

    // ...
    describe('Color model', () => {
      test('displays each mode as an individual button', () => {
        const buttons = wrapper.findAll('.color-mode')
        buttons.wrappers.forEach(button => {
          expect(button.classes()).toEqual(
            expect.arrayContaining([expect.stringMatching(/color-mode-\w{1,}/)])
          )
        })
      })
    })

    Здесь мы ожидаем элементов с классом, который следует за шаблоном «Color-Mode-» + любого символа слова (в Ecmascript, любой символ внутри [A-ZA-Z_0-9] ). Мы могли бы добавить или удалить любой режим, который мы хотим, и тест все равно будет действительным.

    Естественно, прямо сейчас тест не должен потерпеть неудачу, так как нет кнопок с классом Цвет-режим еще. Мы можем заставить его пройти, жесткодируя их в компоненте.

    Теперь мы можем ревертировать этот код, добавив режимы в качестве личных данных в нашем компоненте и итерации на них.

    
    
    export default {
      // ...
      data() {
        return {
          activeSwatch: 0,
          colorModes: ['hex', 'rgb', 'hsl']
        }
      }
    }

    Хорошо! Давайте двигаться дальше.

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

    test('sets the first mode as the selected one by default', () => {
      const firstButton = wrapper.find('.color-mode')
      expect(firstButton.classes()).toContain('active')
    })

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

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

    
    
    export default {
      // ...
      data() {
        return {
          activeSwatch: 0,
          activeMode: 0,
          colorModes: ['hex', 'rgb', 'hsl']
        }
      }
    }

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

    test('sets the color mode button as active when clicked', () => {
      const targetButton = wrapper.findAll('.color-mode').at(2)
      targetButton.trigger('click')
      expect(targetButton.classes()).toContain('active')
    })

    Теперь мы можем добавить @ yclick Директива, поскольку мы сделали с образцами, и сделайте тест Green без рефакторов.

    Тестирование цветового кода

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

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

    Начнем с (неудачной) теста.

    describe('Color code', () => {
      test('displays the default swatch in the default mode', () => {
        expect(wrapper.find('.color-code').text()).toEqual('#e3342f')
      })
    })

    Теперь давайте сделаем этот пропуск, жесткодируя ожидаемый результат в компоненте.

    #e3342f

    Хорошо! Время рефактору. У нас есть сырье в шестнадцатеричном режиме, и мы готовы выводить его в шестнадцатеричном формате. Единственная разница между нашими входными и выходными значениями заключается в том, что мы хотим добавить последнее с помощью хеш-символа. Самый простой способ сделать это с Vue – через вычисляется имущество.

    
    
    export default {
      // ...
      computed: {
        activeCode() {
          return `#${this.swatches[this.activeSwatch]}`
        }
      }
    }

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

    test('displays the code in the right mode when changing mode', () => {
      wrapper.find('.color-mode-hsl').trigger('click')
      expect(wrapper.find('.color-code').text()).toEqual('2°, 76%, 54%')
    })

    Здесь мы изменились на режим HSL, но мы все еще получаем шестнадцатеричный выход. Нам нужно реформировать наш код, чтобы наши ActiveCode Вычисляемое свойство не только знает о текущем цвете, но и текущий цветной режим. Один из способов достижения этого, это создать вычисленные свойства для каждого режима и прокси-сервера через ActiveCode на основе выбранного режима.

    Во-первых, мы должны упростить доступ к текущему цвету и режиму. Прямо сейчас нам нужно сделать поиск массива, который повторяется и делает код трудно читать. Мы можем использовать вычисленные свойства, чтобы обернуть эту логику.

    export default {
      // ...
      computed: {
        // ...
        activeColorValue() {
          return this.swatches[this.activeSwatch]
        },
        activeModeValue() {
          return this.colorModes[this.activeMode]
        }
      }
    }

    Как видите, мы не пишу тесты для этих вычисленных свойств, так как они не являются частью нашего публичного API. Мы будем использовать их позже в нашем выделенном цветовом режиме, вычисляемые свойствами, которые сами будут подтверждены в ActiveCode , который мы тестируем в нашем номере «цветного кода». Все, что мы заботимся о том, это то, что цветовой код отображается, как и ожидалось Так что пользователь может полагаться на них. Как мы получаем информацию о реализации, которые нам нужно быть в состоянии изменить, если это нужно.

    Теперь мы можем написать наши выделенные вычисленные свойства для каждого режима. Мы рассмотрим их имя на тех Colormodes Итак, мы можем сделать поиск на массиве позже ActiveCode вернуть правильный.

    Для шестнадцатеричного вывода мы можем изменить то, что у нас в настоящее время в ActiveCode и рефтектор его использует ActiveColorValue Отказ

    export default {
      // ...
      computed: {
        // ...
        hex() {
          return `#${this.activeColorValue}`
        }
      }
    }

    Теперь давайте модифицируем ActiveCode Итак, оно просыпается правильное вычисленное свойство в зависимости от активного режима.

    export default {
      // ...
      computed: {
        // ...
        activeCode() {
          return this[this.activeModeValue]
        }
      }
    }

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

    Теперь мы хотим написать компьютерное свойство, которая возвращает вывод цвета в режиме HSL. Для этого мы будем использовать Color-Convert , пакет NPM, который позволяет нам преобразовать цвета во многих различных режимах. Мы уже использовали его в наших тестах, поэтому нам не нужно переустановить его.

    import convert from 'color-convert'
    
    export default {
      // ...
      computed: {
        // ...
        hsl() {
          const hslColor = convert.hex.hsl(this.activeColorValue)
          return `${hslColor[0]}°, ${hslColor[1]}%, ${hslColor[2]}%`
        }
      }
    }

    Отлично, наш тест проходит! Теперь мы можем завершить это, добавление отсутствующего режима RGB.

    Тем не менее, как вы можете видеть, мы в настоящее время не тестируем вывод наших цветовых вычисленных свойств в изоляции, но через другие тесты. Чтобы сделать вещи уборщими, мы могли бы отделить эту логику из компонента, импортировать его как зависимость и тестировать его отдельно. Это имеет несколько преимуществ:

    • Он держит компонент от растущего каждый раз, когда мы хотим добавить цветной режим,
    • Он сохраняет домены отделен: компонент фокусируется на своей собственной логике просмотра, а утилита цветовой моды заботится о тестировании каждого режима исчерпывающим.

    Во-первых, создайте новый color.js Файл в SRC/UTILS/ каталог и соответствующий файл спецификации в Тесты/блок/ Отказ

    // color.spec.js
    
    import { rgb, hex, hsl } from '@/utils/color'
    
    // color.js
    
    import convert from 'color-convert'
    
    export const rgb = () => {}
    
    export const hex = () => {}
    
    export const hsl = () => {}

    Мы можем использовать TDD для тестирования этих трех функций и убедиться, что они всегда возвращают ожидаемое значение. Мы можем извлечь логику, которую мы имели в нашем Vue Component для последних двух, и напишите функцию RGB с нуля.

    Ради краткости, мы накроем все три теста одновременно, но процесс остается прежним.

    import { rgb, hex, hsl } from '@/utils/color'
    
    const color = 'e3342f'
    
    describe('color', () => {
      test('returns the color into RGB notation', () => {
        expect(rgb(color)).toBe('227, 52, 47')
      })
      test('returns the color into hexadecimal notation', () => {
        expect(hex(color)).toBe('#e3342f')
      })
      test('returns the color into HSL notation', () => {
        expect(hsl(color)).toBe('2°, 76%, 54%')
      })
    })

    Теперь у нас есть три неудачных теста. Первое, что мы можем сделать, это вернуть жесткозедированные значения для Green.

    export const rgb = () => '227, 52, 47'
    
    export const hex = () => '#e3342f'
    
    export const hsl = () => '2°, 76%, 54%'

    Теперь мы можем начать рефакторинг, мигрируя код из нашего Vue компонента.

    export const hex = () => `#${color}`
    
    export const hsl = color => {
      const hslColor = convert.hex.hsl(color)
      return `${hslColor[0]}°, ${hslColor[1]}%, ${hslColor[2]}%`
    }

    Наконец, мы можем реализовать наше RGB функция.

    export const rgb = color => convert.hex.rgb(color).join(', ')

    Все тесты должны оставаться зелеными!

    Теперь мы можем использовать цвет Утилиты в нашем Vue Component и Refactor это немного. Нам больше не нужно импортировать Color-Convert В компоненте и не нужны выделенные вычисленные свойства для каждого режима или даже для получения активных значений цвета и режима. Все, что нам нужно, чтобы сохранить ActiveCode , где мы можем хранить всю необходимую логику.

    Это хороший пример, где делают тестирование Black Box: мы сосредоточились на тестировании публичных API; Таким образом Мы можем рефакторировать внутренние органы нашего компонента, не нарушая тесты Отказ Удаление свойств, таких как ActiveColorValue или шестнадцатеричный не имеет значения, потому что мы никогда не теряли их напрямую.

    // ...
    import { rgb, hex, hsl } from '@/utils/color'
    
    const modes = { rgb, hex, hsl }
    
    export default {
      // ...
      computed: {
        activeCode() {
          const activeColor = this.swatches[this.activeSwatch]
          const activeMode = this.colorModes[this.activeMode]
          return modes[activeMode](activeColor)
        }
      }
    }

    Теперь у нас есть гораздо код Терсера в нашем компоненте, а лучшим разделением домена, при этом уважаю контракт компонента.

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

    test('displays the code in the right color when changing color', () => {
      wrapper
        .findAll('.swatch')
        .at(2)
        .trigger('click')
      expect(wrapper.find('.color-code').text()).toEqual('#f6993f')
    })

    И мы закончили! Мы просто построили полностью функциональный VUE компонент, используя TDD, не полагаясь на вывод браузера, И наши тесты готовы Отказ

    Визуальный контроль

    Теперь, когда наш компонент готов, мы видим, как он выглядит и играет с ним в браузере. Это позволяет нам добавлять CSS и убедиться, что мы не пропустили ни о чем.

    Во-первых, установите компонент в главную App.vue файл.

    
    
    
    
    

    Затем запустите приложение, выполнив следующий скрипт и откройте его в браузере на http://localhost: 8080/ Отказ

    npm run serve

    Вы должны увидеть ваш сборщик цветов! Это не похоже на некоторое время, но это работает. Попробуйте щелкнуть цвета и изменить цветной режим; Вы должны увидеть изменение цветового кода.

    Чтобы увидеть компонент с надлежащим стилем, добавьте следующие CSS между Стиль Теги:

    .color-picker {
      background-color: #fff;
      border: 1px solid #dae4e9;
      border-radius: 0.125rem;
      box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
      color: #596a73;
      font-family: BlinkMacSystemFont, Helvetica Neue, sans-serif;
      padding: 1rem;
    }
    
    .swatches {
      color: #fff;
      display: flex;
      flex-wrap: wrap;
      list-style: none;
      margin: -0.25rem -0.25rem 0.75rem;
      padding: 0;
    }
    
    .swatch {
      border-radius: 0.125rem;
      cursor: pointer;
      height: 2rem;
      margin: 0.25rem;
      position: relative;
      width: 2rem;
    }
    
    .swatch::after {
      border-radius: 0.125rem;
      bottom: 0;
      box-shadow: inset 0 0 0 1px #dae4e9;
      content: '';
      display: block;
      left: 0;
      mix-blend-mode: multiply;
      position: absolute;
      right: 0;
      top: 0;
    }
    
    .swatch svg {
      display: none;
      color: #fff;
      fill: currentColor;
      margin: 0.5rem;
    }
    
    .swatch.active svg {
      display: block;
    }
    
    .color-modes {
      display: flex;
      font-size: 1rem;
      letter-spacing: 0.05rem;
      margin: 0 -0.25rem 0.75rem;
    }
    
    .color-mode {
      background: none;
      border: none;
      color: #9babb4;
      cursor: pointer;
      display: block;
      font-weight: 700;
      margin: 0 0.25rem;
      padding: 0;
      text-transform: uppercase;
    }
    
    .color-mode.active {
      color: #364349;
    }
    
    .color-code {
      border: 1px solid #dae4e9;
      border-radius: 0.125rem;
      color: #364349;
      text-transform: uppercase;
      padding: 0.75rem;
    }

    Вы должны увидеть что-то вроде этого:

    И мы закончили!

    Последующие

    Как мы можем улучшить это?

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

    Во-первых, вы можете заметить, что при нажатии на белый образец галочка не отображается. Это не ошибка, скорее визуальная проблема: галочка там, но мы не видим это, потому что это белый на белом. Вы можете добавить немного логики, чтобы исправить это: когда цвет легче, чем определенный порог (скажем 90%), вы можете добавить свет класс на образцах. Это позволит вам применить некоторые конкретные CSS и сделать галочку темной.

    К счастью, у вас уже есть все, что вам нужно: Color-Converter Пакет может помочь вам определить, является ли цвет легким (с утилитами HSL), а у вас уже есть цвет Утилита модуль для хранения этой логики и проверять его в изоляции. Чтобы увидеть, как может выглядеть готовый код, проверьте хранилище проекта на Github Отказ

    Мы также могли бы усилить набор, добавив несколько тестов, чтобы убедиться, что некоторые ожидаемые классы там. Это не проверяет фактическую логику, но все равно будет особенно полезен, если кто-то полагается на те имена классов для стиля компонента снаружи. Опять же, все зависит от вашего применения.

    Что мы узнали?

    Есть несколько уроков, чтобы узнать из этого эксперимента TDD. Он много приводит к столу, но также подчеркивает несколько проблем, о которых мы должны знать.

    Во-первых, TDD является Фантастический способ написать надежные испытания , не слишком много, а не слишком мало. Вы когда-нибудь закончили компонент, переехали на тесты и думали «Где я даже начинаю?» ? Глядя на готовый код и выясняет, что тестировать сложно. Заманчиво получить его быстро, упускать из виду некоторые критические части и в конечном итоге с неполным тестовым номером. Или вы можете принять оборонительный подход и проверить все, рискуя сосредоточиться на деталях реализации и написания хрупких испытаний.

    Принятие TDD для разработки компонентов UI помогает нам сосредоточиться на том, что тестировать Определение, перед записью любой строки кода, если это является частью договора или нет Отказ

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

    С TDD, Вы создаете более глубокое соединение между кодом и тестами, с сильным фокусом на создание публичных API надежного Отказ Реализация приходит сразу после того, как вы гарантировали результат. Вот почему зеленый Шаг имеет решающее значение: сначала нужно пройти тест, чтобы убедиться, что он никогда не разрывается. Вместо того, чтобы реализовать свой путь к рабочему решению, вы переворачиваете отношения, сосредотачиваясь на договоре сначала договора, и позволяя реализации оставаться одноразовой. Поскольку Refactoring приходит последнее, и вы установили контракт, теперь у вас есть психическое пространство, чтобы сделать все правильно, чистить какой-то код, принять лучший дизайн или сосредоточиться на производительности.

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

    С другой стороны, идя с TDD для тестирования компонентов пользовательского интерфейса, сначала может быть сложно и требует некоторых предшествующих знаний перед погружением в него. Для начала, Вы должны иметь хорошие знания о ваших библиотеках тестирования Так что вы можете написать надежные утверждения. Посмотрите на тест, который мы написали с регулярным выражением: синтаксис не является наиболее простым. Если вы не знаете библиотеку хорошо, легко написать тест, который не выполняет не по темвания причинам, что затруднит весь процесс TDD.

    Точно так же вы должны знать о некоторых деталях, касающихся ожидаемых ценностей; В противном случае вы можете в конечном итоге бороться с тестами и делать некоторые раздражающие обратные вещи. В этом отношении компоненты пользовательского интерфейса являются более сложными, чем рендеренные библиотеки, из-за различных способов реализованы спецификации DOM.

    Сделайте первый тест нашего набора, например: мы тестируем цвета фона. Однако, хотя мы проходим шестнадцатеричные цвета, мы ожидаем возвратных значений RGB. Это потому, что шутка использует jsdom Node.js внедрение стандартов DOM и HTML. Если бы мы работали наши тесты в конкретном браузере, у нас может быть другое возвращаемое значение. Это может быть сложно, когда вы тестируете разные двигатели. Возможно, вам придется искать более современные утилиты преобразования или используйте переменные среды для обработки различных реализаций.

    Стоит ли оно того?

    Если вы сделали это так далеко, вы, наверное, поняли, что TDD требует времени Отказ Эта статья сама более 6000 слов! Это может быть немного страшно, если вы привыкли к более быстрому циклам развития, и, вероятно, выглядит невозможно, если вы часто работаете под давлением. Тем не менее, важно разорить миф, что TDD каким-то образом будет удвоить время разработки для небольшого возврата инвестиций, потому что это совершенно ложно.

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

    Во-вторых, Время, потраченное на написание тестового кода, – время, когда вы не будете тратить крепежные ошибки Отказ

    Исправления ошибок гораздо дороже, чем предотвратить их. Если вам когда-либо приходилось исправить критические производственные ошибки, вы знаете, что это чувствует себя близко к удержанию открытой раны на хирургическом пациенте одной рукой, пытаясь работать с другой. В пустыне. Ночью, вечером. Со швейцарским армейским ножом. Это грязно, стрессовый, субоптимальный и несет высокие шансы на то, чтобы привернуть что-то еще в процессе. Если вы хотите сохранить свое здравоохранение и доверие, ваши конечные пользователи имеют в вашем программном обеспечении, Вы хотите избежать этих ситуаций вообще расходы Отказ

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

    Как и ни с чем, я рекомендую вам попробовать TDD, прежде чем отбрасывать идею. Если вы постоянно столкнулись с проблемами производства, или вы думаете, что можете улучшить свой процесс разработки, тогда стоит дать ему выстрел. Попробуйте в течение ограниченного количества времени, измерить влияние и сравните результаты. Вы можете обнаружить метод, который поможет вам отправить лучшее программное обеспечение и чувствовать себя уверенно, чтобы ударить кнопку «Развернуть».