На днях я играл с библиотекой include-media от Eduardo Bouças и хотел быстро протестировать созданную мной функцию, поэтому я начал писать небольшой миксин, чтобы помочь мне протестировать множество различных сценариев. Через пару минут я придумал самый минималистичный движок тестирования Sass, какой только можно было получить.
Хотя эта статья может быть немного технической, я считаю, что она может быть полезна для многих, так как тестирование должно быть обязанностью каждого разработчика. Кроме того, когда вы будете разбираться с вещами одна за другой, вы увидите, что на самом деле это не так сложно понять.
Создание фиктивной функции для тестирования
Все начинается с функции для тестирования. Для нашей цели я предлагаю перейти с очень простой функцией. Допустим, функция для удвоения числа.
@function double($value) { @return $value * 2; }
Звучит достаточно просто. Хотя, и только для наших демонстрационных задач, мы собираемся добровольно внести ошибку в нашу функцию, чтобы мы могли увидеть, что один из наших тестов завершился неудачей.
@function double($value) { // Voluntarily introduced bug for demonstration purpose @if $value == 3 { @return 5; } @return $value * 2; }
Написание тестов
Это может показаться удивительным, но написание тестов в нашей системе так же просто, как написание карты Sass, где ключи — это входные данные функций, а значения — ожидаемые результаты.
$tests-double: ( 1: 2, 2: 4, 3: 6, 4: 8 );
Это оно! Мы написали наши тесты. Опять же: с левой стороны находятся входы, а с правой стороны ожидаемые выходы.
Тестовый бегун
Все идет нормально. Мы создали нашу функцию и написали наши тесты. Теперь нам нужно только создать тестового бегуна.
Если вы знакомы с Sass, возможно, вы уже поняли, куда это идет. Наш тестовый исполнитель собирается выполнить итерацию на тестовой карте, вызывая функцию для каждого входа и проверяя, соответствует ли она ожидаемому результату. Затем он напечатает результат наших тестов.
Вот как выглядит наш тестовый бегун:
/// Run a function ($function) on a test suite ($tests) /// @param {Map} $tests - Test suite /// @param {String} $function - Name of function to test @mixin run-tests($tests, $function) { .. }
Хорошо. Давайте копаться в живот зверя. Идея состоит в том, чтобы создать строку с результатом каждого теста, и после того, как все будет сделано, напечатайте строку с директивой @error
. Например, мы могли бы передать его в свойство content
@error
, но это немного сложнее, поэтому мы будем придерживаться @error
.
Первое, что нужно сделать, это выполнить итерацию набора тестов. Для каждого теста мы динамически вызываем функцию по ее имени (с помощью функции call(..)
) и проверяем, соответствует ли результат ожидаемому.
@mixin run-tests($tests, $function) { $output: ''; @each $test, $expected-result in $tests { $result: call($function, $test...); @if $result == $expected-result { // Test passed $output: $output + 'Test passed; '; } @else { // Test failed $output: $output + 'Test failed; '; } } // Print output @error $output; }
На данный момент наша система работает. Давайте запустим его в нашем тестовом наборе, чтобы посмотреть, как он выглядит.
@include run-tests($tests-double);
Test passed; Test passed; Test failed; Test passed;
Привет! Это начало правильно? Теперь нам нужно только сделать вывод немного более полезным (и дружественным).
Прокачка выходного
Это момент, когда вы можете настроить вывод, чтобы он выглядел так, как вы хотите. Нет единого способа сделать это, вы можете вывести все, что пожелаете. Обратите внимание, что в соответствии со спецификацией CSS, вы можете иметь разрыв строки в вашей строке, используя \a
.
В моем случае вот что я сделал:
@mixin run-tests($tests, $function) { $output: ''; $length: length($tests); $failing: 0; @each $test, $expected-result in $tests { $result: call($function, $test...); $test-index: index(map-keys($tests), $test); $output: $output + '\a Test #{$test-index} out of #{$length}... '; @if $result == $expected-result { // Test passed $output: $output + '✔'; } @else { // Test failed $failing: $failing + 1; $output: $output + '✘\a Expected : `#{$expected-result}`.\a Actual : `#{$result}`.'; } } // Print output @error 'Started tests for function `#{$function}`\a ' + '-----------------------------------' + $output + '\a ' + '-----------------------------------\a ' + 'Over: #{$length - $pass} test(s) out of #{$length} failing.'; }
Если мы снова запустим его на нашем $tests-double
для функции double
, вот что мы получили:
Started tests for function `double` ----------------------------------- Test 1 out of 4... Test 2 out of 4... Test 3 out of 4... ✘ Expected : `6`. Actual : `5`. Test 4 out of 4... ----------------------------------- Over: 1 test(s) out of 4 failing.
Теперь это довольно опрятно, не так ли?
Тестирование функций с несколькими аргументами
В нашем примере у нашей функции был один аргумент, но мы можем положиться на тот факт, что карты Sass принимают что угодно в качестве ключей (включая списки) для тестирования функций с несколькими параметрами. Это будет выглядеть так:
@function my-function($string, $color, $length) { .. } $tests-my-function: ( ('a', red, 42px): 'My expected result', // ... );
Если вы посмотрите на наш миксин, то увидите, что мы добавляем многоточие ( ...
) к переменной $test
при вызове функции с call(..)
.
$result: call($function, $test...);
Это означает, что мы передаем значение $test
как arglist
. Другими словами, если $test
— это список (например, ('a', red, 42px)
), тогда он будет передан как несколько аргументов, а не как список.
Последние мысли
Вот вам, ребята, самый минималистичный движок для тестирования Sass. Эта крошечная система тестирования может оказаться очень полезной для тестирования тех немногих функций, которые могут быть в вашем проекте, особенно если вы планируете предоставлять ее другим разработчикам (фреймворк, библиотека…). Кроме того, я обнаружил, что очень удобно быстро протестировать функцию на SassMeister. Просто поместите туда свой миксин и свою функцию и запустите свои тесты!
Конечно, если вы ищете более глубокое решение, возможно, вы захотите взглянуть на True Эрика Сюзанна. Как полноценная среда тестирования для Sass, она больше подходит для глобальной инфраструктуры модульных тестов.
Если вы хотите взглянуть на (немного более продвинутую версию) кода, я открыл репозиторий SassyTester, чтобы собрать все.
Так что ты думаешь?