Как проверить результат мини-обработки JavaScript - программирование
Подтвердить что ты не робот

Как проверить результат мини-обработки JavaScript

Недавно мы обновили до новой сборки библиотеки миниатюр JavaScript.

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

(Урок Life: не обновляйте JS minifiers, если вы действительно не уверены, что вам нужна новая версия.)

minifier используется для кода JavaScript на стороне клиента с большим вниманием к деятельности, связанной с DOM, а не почти так же "бизнес-логикой".

Упрощенный пример того, что было нарушено при обновлении minifier:

function process(count)
{
     var value = ""; 
     value += count; //1. Two consecutive += statements
     value += count;
     count++;        //2. Some other statement
     return value;   //3. Return
}

Недопустимо неверно присвоено значение:

function process(n){var t="";return t+n+n,n++,t}

Хотя мы могли бы написать некоторые модульные тесты, чтобы уловить некоторые из возможных проблем, учитывая, что JavaScript тяжелый для взаимодействия с DOM (ввод данных и т.д.), очень сложно тщательно протестировать без тестирования пользователя (неавтоматизированным). Мы размышляли об использовании библиотеки JS в AST, такой как Esprima, но учитывая характер изменений, которые могут быть внесены в минифицированный код, это создало бы слишком много ложных срабатываний.

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

FYI: это очень сложное веб-приложение с несколькими сотнями тысяч строк кода JavaScript.

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

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

Обновление:

Одна из наших идей заключалась в следующем:

  • принять предупреждение со старой версией
  • украсить его
  • minify с новой версией,
  • украсить, и
  • визуально diff.

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

4b9b3361

Ответ 1

Вы считали структуру unit test, например QUnitjs? Было бы довольно много работы, чтобы написать модульные тесты, но в итоге у вас будет повторяющаяся процедура тестирования.

Ответ 2

Звучит для меня так, как будто вам нужно начать использовать автоматические тесты устройств в вашей CI (среда непрерывной интеграции). QUnit был запущен, но на самом деле QUnit - довольно слабая система тестирования, и его утверждения - это barebones как минимум (он даже не использует хороший синтаксис на основе утверждений). Он лишь незначительно квалифицируется как TDD и не очень хорошо справляется с BDD.

Лично я бы рекомендовал Jasmine с JsTestDriver (он может использовать другие UT-рамки или свои собственные, и это невероятно быстро... хотя у него есть некоторые проблемы с стабильностью, которые я действительно желаю, чтобы они исправили), и установки модульных тестов, которые могут проверять процессы минимизации несколькими сравнениями.

Некоторые сравнения, вероятно, должны быть:

  • оригинальный код и его функциональность ведут себя как ожидалось
  • по сравнению с минитипированным кодом (здесь BDD входит в систему, ожидайте такую ​​же функциональную производительность/результаты в сокращенном коде)
  • Я бы сделал еще один шаг (в зависимости от вашего подхода к минимизации) и проверил тест, который затем украсит мини-оценку и проведет другое сравнение (это делает ваше тестирование более надежным и более гарантированным).

Эти типы тестов - это то, почему вы, вероятно, выиграли бы от BDD-совместимой структуры, такой как Jasmine, в отличие от просто чистого TDD (например, результаты, которые вы обнаружили в визуальном различии, являющемся бесполезным), поскольку вы тестируете поведение и сравнения и состояния предшествующего/постсостояния функциональности/поведения, а не только если a истинно и по-прежнему истинно после анализа.

Настройка этих тестов модулей может занять некоторое время, но это итеративный подход с такой большой кодовой базой... быстро и рано проверять ваши начальные критические точки затухания или хрупкие точки, а затем распространять тесты на все (так, я всегда устанавливал свои команды в том, что все, что с этого момента не считается полным, и RC, если у него нет Unit Tests... ничего старого, у которого нет тестов Unit, и который должен быть обновлен/затронут/сохранен, должен иметь Unit Tests, написанный, когда они касаются, так что вы постоянно улучшаете и уменьшаете количество непроверенного кода более управляемым и логичным способом, увеличивая охват кода).

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

Проблема, которую вы описываете, - это то, что были построены для CI и Unit Tests, а более конкретно в вашем случае этот подход минимизирует влияние размера кодовой базы... размер не делает его более сложным, просто делает продолжительность дольше тестировать работу над доской.

Затем объедините это с JSDoc3, и вы станете лучше 90% от большинства магазинов переднего конца. В этот момент он невероятно прочен и полезен для инженеров, и он становится самовоспроизводящимся.

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

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

Ответ 3

Вы можете посмотреть что-то вроде Selenium Web Driver, который позволяет автоматизировать тесты для веб-приложений в различных средах. Есть несколько облачных решений VM для проведения многоуровневого тестирования, поэтому вы не попадаете в Webkit, но не в IE.

Ответ 4

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

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

ознакомьтесь с этой статьей на исходных картах: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

также проверьте документацию для компилятора замыкания, он получил предложения о том, как писать лучший код для минимизации: https://developers.google.com/closure/compiler/

Ответ 5

Не тестовое решение, но как насчет перехода на TypeScript для написания больших приложений JS, таких как ваши?

Я тестировал его с помощью TypeScript и его минимального двигателя по умолчанию, и он отлично работает.

Предполагая, что ваш аргумент count является числом.

Тип script будет:

class ProcessorX {
    ProcessX(count: number): string {
        var value = '';
        value += count.toString();
        value += count.toString();
        count++;
        return value;
    }
}

Что создает js следующим образом:

var ProcessorX = (function () {
    function ProcessorX() { }
    ProcessorX.prototype.ProcessX = function (count) {
        var value = '';
        value += count.toString();
        value += count.toString();
        count++;
        return value;
    };
    return ProcessorX;
})();

Затем округляется до:

var ProcessorX=function(){function n(){}return n.prototype.ProcessX=function(n){var t="";return t+=n.toString(),t+=n.toString(),n++,t},n}()

На jsfiddle.

Если ваш count является string, тогда fiddle.

Ответ 6

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