суббота, 3 марта 2012 г.

Безбраузерное тестирование javascript кода


Безбраузерное тестирование
Автоматизированное тестирование javascript
Автоматизированное тестирование с помощью Rhino + QUnit
Работа с отладчиком Rhino
Автоматизированное тестирование с помощью Rhino + Jasmine
Тестирование AJAX вызовов в безбраузерной среде с помощью Jasmine



Безбраузерное тестирование

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

До тех пора, пока приложение является небольшим, тестирование автоматизированное или ручное в браузере является терпимым. Однако более практичным представляется атоматизированное безбраузерное тестирование.  Разумеется недостатком такого подхода является то, что мы не можем проследить как ведёт себя код в разных браузерах, но это может стать подспорьем при разработке приложения. Для ручного тестирования в различных браузерах рекомендуется использовать либо отдельные виртуальные машины для каждого браузера либо использовать набор IE Collection (http://utilu.com/IECollection/).

Для безбраузерного тестирования нам понадобится javascript движок. На февраль 2012 года известны следующие движки javascript:
Rhino: Mozilla’s Java JavaScript implementation.
SpiderMonkey: Mozilla’s C implementation of JavaScript.
V8: Google’s JavaScript virtual machine for Chrome.

Автоматизированное тестирование javascript



Мне пока известны следующие подходы к тестированию:

1) на базе Node.js
2) на базе движка Rhino от Mozilla

Рассмотрим второй подход.

Для этого можно использовать:  
  1. Rhino - реализация javascript на java.
  2. Envjs - реализация DOM API для Rhino. Эту библиотеку разработал разработчик jQuery.
  3. Jasmine - библиотека для тестирования.
  4. Jquery-jasmine - упрощение тестирования jasmine и DOM.
  5. QUnit - ещё одна библиотека для тестирования.

Автоматизированное тестирование с помощью Rhino + QUnit


Попробуем поставить Rhino и заставить работать Envjs.
1) Скачиваем Rhino rhino1_7R2 с сайта  Mozilla ftp://ftp.mozilla.org/pub/mozilla.org/js/rhino1_7R2.zip.
Распаковываем архив. В этом архиве нам потребуется файл js.jar.
Теперь проверим, что Rhino действительно работает.
Для этого запустим команду
java -cp js.jar org.mozilla.javascript.tools.shell.Main -opt -1

Затем введём команду print("Hello world");
quit();

Далее необходимо установить Envjs.
Установим пропатченную версию Envjs.
Для этого скачаем её по ссылке https://github.com/ryan-roemer/envjs-1.2.

Скачаем также QUnit - система для создания тестов.
https://github.com/jquery/qunit/blob/a46610796b457fab05587945e743d4e857f580b5/qunit/qunit.css
https://github.com/jquery/qunit/blob/a46610796b457fab05587945e743d4e857f580b5/qunit/qunit.js


Теперь нам надо будет создать ещё два файла:
setup.js - для интеграции Envjs с QUnit.
run-tests.js - скрипт для запуска тестов.

Создадим файл my-lib.js с тестируемой функцией:
function addTwo(x, y) {
   return x + y;
}

Создадим файл my-tests.js с QUnit тестом.
module("My Module");

test("addTwo", function () {
   equals(addTwo(0, 0), 0, "Add nothing.");
   equals(addTwo(1, 2), 3, "Add numbers.");
   equals(addTwo(-1, -2), -3, "Add negatives.");
});

Теперь создадим страницу test.html:
<html>
 <head>
   <title>QUnit</title>
   <link rel="stylesheet" href="qunit.css" type="text/css" />
   <script type="text/javascript" src="qunit.js"></script>
   <script type="text/javascript" src="my-lib.js"></script>
   <script type="text/javascript" src="my-tests.js"></script>
 </head>
 <body>
   <h1 id="qunit-header">QUnit Test Suite</h1>
   <h2 id="qunit-banner"></h2>
   <div id="qunit-testrunner-toolbar"></div>
   <h2 id="qunit-userAgent"></h2>
   <ol id="qunit-tests"></ol>
   <div id="qunit-fixture"></div>
 </body>
</html>

После того, как мы убедились, что в браузере файл test.html выполняется, можно настроить
Envjs и Qunit.

Создадим файл setup.js со следующим содержимым:
load('env.rhino.1.2.js');
load('qunit.js');

var starttime = new Date().getTime();

// Envjs/QUnit Bridge.
Envjs({
   // Straight from the Envjs guide.
   scriptTypes: {
       "": true,
       "text/javascript": true
   },
   // Straight from the Envjs guide.
   beforeScriptLoad: {
       'sharethis': function (script) {
           script.src = '';
           return false;
       }
   },

   // Hook QUnit logging to console.
   afterScriptLoad: {
       'qunit': function () {
           var count = 0, testName;

           console.log("* QUnit test runner loaded.");

           // Grab current test name.
           QUnit.testStart = function(name, testEnvironment) {
               testName = name;
           };
           // Override log to display to stdout.
           QUnit.log = function (result, message) {
               // Strip out HTML in results messages.
               message = message.replace(/<\/?.*?>/g, '');
               console.log("  * {%s}(%s)[%s] %s",
                   testName, count++,
                   result ? 'PASS' : 'FAIL', message);
           };
           QUnit.done = function (fail, total){
               var endtime = new Date().getTime();
               var pass = total - fail;
               console.log("\n" +
                   "*****************\n" +
                   "* QUnit Results *\n" +
                   "*****************\n" +
                   "* PASSED: %s\n" +
                   "* FAILED: %s\n" +
                   "* Completed %s tests total in %s seconds.\n",
                   pass, fail, total,
                   parseFloat(endtime-starttime) / 1000.0);
          };
       },

       // Straight from the Envjs guide.
       '.': function (script) {
           script.type = 'text/envjs';
       }
   }
});

Создадим теперь скрипт для запуска тестов run-tests.js:
load('setup.js');

console.log("Starting QUnit tests...");
window.location = "test.html";

Теперь проверим как всё это работает.
Выполним команду
java -cp ~/rhino1_7R2/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 run-tests.js

[duglas@vmstation js]$ java -cp ~/projects/Rhino/rhino1_7R2/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 run-tests.js
[  Envjs/1.6 (Rhino; U; Linux i386 2.6.32.11-99.fc12.i686; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13  ]
Starting QUnit tests...
* QUnit test runner loaded.
 * { addTwo }( 0 )[ PASS ]  Add nothing.
 * { addTwo }( 1 )[ PASS ]  Add numbers.
 * { addTwo }( 2 )[ PASS ]  Add negatives.

*****************
* QUnit Results *
*****************
* PASSED:  3
* FAILED:  0
* Completed  3  tests total in  3.233  seconds.

[duglas@vmstation js]$ java -cp ~/projects/Rhino/rhino1_7R2/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 run-tests.js
[  Envjs/1.6 (Rhino; U; Linux i386 2.6.32.11-99.fc12.i686; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13  ]
Starting QUnit tests...
* QUnit test runner loaded.
 * { addTwo }( 0 )[ PASS ]  Add nothing.
 * { addTwo }( 1 )[ PASS ]  Add numbers.
 * { addTwo }( 2 )[ PASS ]  Add negatives.

*****************
* QUnit Results *
*****************
* PASSED:  3
* FAILED:  0
* Completed  3  tests total in  3.466  seconds.

Ура!
Заработали наши тесты.

Работа с отладчиком Rhino

Чтобы вызвать отладчик Rhino необходимо выполнить команду:
java -cp js.jar org.mozilla.javascript.tools.debugger.Main


Автоматизированное тестирование с помощью Rhino + Jasmine


Скачаем Jasmine по ссылке https://github.com/downloads/pivotal/jasmine/jasmine-0.10.0.zip.
Скачаем Jasmie-reporters по ссылке https://github.com/larrymyers/jasmine-reporters.  Этот проект представляет собой набор из подключаемых адаптеров для форматирования результатов теста.

По умолчанию Jasmine использует TrivialReporter для отображения результатов тестов в браузере. Jasmie-reporters содержит ConsoleReporter для вывода результатов в консоль и JUnitXmlReporter - для формирования отчёта в формате JUnit.

Создадим пример теста Jasmine и ConsoleReporter.


Создадим модель Калькулятора.
Для этого создадим файл calc.js со следующим содержимым:

/*
   Класс калькулятора
*/

var Calculator = function(){
return {
    add: function(a,b){
       return a+b;
    },
    sub: function(a,b){
       return a-b;
    },
    div: function(a,b){
       return a/b;
    },
    mul: function(a,b){
       return a*b;
    },
    writeTofile: function(filename, text){
       try {
               var out = new java.io.BufferedWriter(new java.io.FileWriter(filename));
               out.write(text);
               out.close();
               return;
           } catch (e) {}
    }
}
};

Создадим файл calc-test.js с нашими тестами:

           describe('калькулятор',function(){
               var calc = Calculator();
               it('Складываем 1 и 2',function(){
                   var result = calc.add(1,2);
                   expect(result).toEqual(3);
               });
               
               it('Вычитаем 1 и 2',function(){
                   var result = calc.sub(1,2);
                   expect(result).toEqual(-1);
               });
               
           });

Мы написали 1 модуль с 2 тестами. Один тест на сложение двух чисел, а второй тест на вычитание двух чисел. Нам также понадобятся следующие файлы:
env.rhino.1.2.js
jasmine.console_reporter.js
jasmine.css
jasmine.js
jasmine-html.js
jquery-1.6.2.min.js

Создадим файл setup.js, который будет загружать DOM модель в Rhino:
load('env.rhino.1.2.js');
Envjs.scriptTypes['text/javascript'] = true;  

Создадим файл index.html, представляющий собой нашу страницу:
<html>
<head>
<link rel="stylesheet" type="text/css" href="jasmine.css">
 <script type="text/javascript" src="jasmine.js"></script>
 <script type="text/javascript" src="jasmine-html.js"></script>
<script type="text/javascript" src="jquery-1.6.2.min.js"></script>
 <script type="text/javascript" src="jasmine.console_reporter.js"></script>
 <script type="text/javascript" src="calc.js"></script>
 <script type="text/javascript" src="calc-test.js"></script>
</head>
<body>

<script type="text/javascript">
   (function($){
       $(document).ready(function(){
           var jasmineEnv = jasmine.getEnv();
       
         var trivialReporter = new jasmine.TrivialReporter();

         jasmineEnv.addReporter(trivialReporter);
                 jasmineEnv.addReporter(new jasmine.ConsoleReporter());
         
       
           jasmineEnv.execute();
           
           var calc = Calculator();
           //calc.writeTofile('./test.txt','мой простой текст');
       })    
   })(jQuery);
   
   
</script>
   <div  >
   <p>
       http://net.tutsplus.com/tutorials/javascript-ajax/testing-your-javascript-with-jasmine/ - интересная страница по jasmine
       http://www.build-doctor.com/2010/12/08/javascript-bdd-jasmine
       https://github.com/velesin/jasmine-jquery
       http://stanislavvitvitskiy.blogspot.com/2009/04/calling-java-from-xul-applications.html
$ java -cp ~/rhino1_7R2/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 run-tests.js

   </p>    
   </div>
</body>
</html>

Теперь нам нужен файл для запуска непосредственно процесса тестирования. Содержимое файла run-tests.js:
load('setup.js');

console.log("Starting Jasmine tests...");
window.location = "index.html";

Запустим тесты с помощью следующей команды :
[duglas@vmstation jasminetest]$ java -cp ~/projects/Rhino/rhino1_7R2/js.jar org.mozilla.javascript.tools.shell.Main -opt -1 run-tests.js
[  Envjs/1.6 (Rhino; U; Linux i386 2.6.32.11-99.fc12.i686; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13  ]
Starting Jasmine tests...
Runner Started.
калькулятор : Складываем 1 и 2 ...
Passed.
калькулятор : Вычитаем 1 и 2 ...
Passed.
калькулятор: 2 of 2 passed.
Runner Finished.
2 specs, 0 failures in 0.087s.

Таким образом мы смогли выполнить jasmine тесты, а результат своей работы вывели в консоль.

Очень легко подключить JUnitXmlReporter. Для этого необходимо вставить строчку <script type="text/javascript" src="jasmine.junit_reporter.js"></script>
в раздел подключаемых скриптов и подключить новый адаптер в коде jasmineEnv.addReporter(new jasmine.JUnitXmlReporter());

После прогона тестов будет создан xml файл вида TEST-<имя спецификации>.xml, который можно обрабатывать в JUnit.



Тестирование AJAX вызовов в безбраузерной среде с помощью Jasmine

Пока не очень понятно, что можно написать.
В данном случае возможны следующие виды тестирования:
  1. Unit тесты, которые подменяют AJAX запросы и позволяют выполнять код до вызова AJAX запроса и сразу после него. Также можно подменять ответ от сервера.
  2. Интеграционные тесты, которые выполняют настоящие AJAX запросы.


Jasmine имеет поддержку и тех и других видов тестов.

Также написан плагин jasmine-ajax. Найти его можно по ссылке https://github.com/pivotal/jasmine-ajax. Этот плагин совместим с jQuery и Prototype.  Плагин подменяет AJAX вызовы и таким образом не один запрос не уйдёт на сервер.

Комментариев нет:

Отправить комментарий