Автоматическое модульное тестирование с JavaScript - PullRequest
60 голосов
/ 18 сентября 2008

Я пытаюсь включить некоторые модульные тесты JavaScript в мой автоматизированный процесс сборки. В настоящее время JSUnit хорошо работает с JUnit, но, похоже, он заброшен и не имеет хорошей поддержки AJAX, отладки и тайм-аутов.

У кого-нибудь была удача в автоматизации (с помощью ANT) библиотеки модульного тестирования, такой как тест YUI, JQuery's QUnit или jQUnit (http://code.google.com/p/jqunit/)?

Примечание. Я использую пользовательскую библиотеку AJAX, поэтому проблема с DOH в Dojo заключается в том, что для работы с любым модульным тестированием AJAX требуется использовать их собственные вызовы функций AJAX и обработчики событий.

Ответы [ 14 ]

24 голосов
/ 19 сентября 2008

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

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

Я также собираюсь использовать JSCoverage , чтобы получить анализ покрытия кода тестами. Это также будет автоматизировано с помощью Selenium.

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


Инструменты тестирования:

19 голосов
/ 18 сентября 2008

Существует много фреймворков для модульных тестов javascript (jsUnit, scriptaculous, ...), но я знаю, что jsUnit может использоваться с автоматической сборкой.

Если вы проводите «настоящий» модульный тест, вам не нужна поддержка AJAX. Например, если вы используете инфраструктуру ajax RPC, такую ​​как DWR, вы можете легко написать фиктивную функцию:

   function mockFunction(someArg, callback) {
      var result = ...; // some treatments   
      setTimeout(<br>
        function() { callback(result); }, 
        300  // some fake latency<br>
      );
    }

И да, JsUnit обрабатывает таймауты: Моделирование времени в тестах jsUnit

13 голосов
/ 03 ноября 2009

Я большой поклонник js-test-driver

Он хорошо работает в среде CI и способен захватывать реальные браузеры для кросс-браузерного тестирования.

4 голосов
/ 19 октября 2010

Я только что заставил Хадсона CI запустить JasmineBDD (без головы), по крайней мере, для чистого тестирования javascript

(Хадсон работает с Java через оболочку, работает Envjs, работает JasmineBDD.)

У меня пока нет возможности играть с большой библиотекой, как с прототипом.

4 голосов
/ 26 сентября 2008

Недавно я прочитал статью Бруно, используя JsUnit и создавая фреймворк JsMock, очень интересный. Я думаю об использовании его работы, чтобы начать модульное тестирование моего кода Javascript.

Mock Javascript или Как выполнить модульное тестирование Javascript вне среды браузера

2 голосов
/ 12 декабря 2009

Я согласен, что Джунит умирает на корню. Мы только что закончили замену его на YUI Test.

Как и в примере с qUnit, мы запускаем тесты с использованием Selenium. Мы запускаем этот тест независимо от других наших тестов селена просто потому, что в нем нет зависимостей, которые есть у обычных регрессионных тестов пользовательского интерфейса (например, развертывание приложения на сервере).

Для начала у нас есть базовый файл javascript, который включен во все наши тестовые html-файлы. Это позволяет настроить экземпляр YUI, тестовый прогон, объект YUI.Test.Suite, а также Test.Case. У него есть методы, к которым можно обратиться через Selenium для запуска набора тестов, проверить, запущен ли еще тестер (результаты недоступны до его завершения), и получить результаты теста (мы выбрали формат JSON)

var yui_instance; //the YUI instance
var runner;  //The YAHOO.Test.Runner
var Assert; //an instance of YAHOO.Test.Assert to save coding
var testSuite; //The YAHOO.Test.Suite that will get run.

/**
 * Sets the required value for the name property on the given template, creates
 * and returns a new YUI Test.Case object.
 * 
 * @param template the template object containing all of the tests
 */
function setupTestCase(template) {
    template.name = "jsTestCase";
    var test_case = new yui_instance.Test.Case(template);
    return test_case;
}

/**
 * Sets up the test suite with a single test case using the given 
 * template.
 * 
 * @param template the template object containing all of the tests
 */
function setupTestSuite(template) {
    var test_case = setupTestCase(template);
    testSuite = new yui_instance.Test.Suite("Bond JS Test Suite");
    testSuite.add(test_case);
}

/**
 * Runs the YAHOO.Test.Suite
 */
function runTestSuite() {
    runner = yui_instance.Test.Runner;
    Assert = yui_instance.Assert;

    runner.clear();
    runner.add(testSuite);
    runner.run();
}

/**
 * Used to see if the YAHOO.Test.Runner is still running.  The
 * test results are not available until it is done running.
 */
function isRunning() {
    return runner.isRunning();
}

/**
 * Gets the results from the YAHOO.Test.Runner
 */
function getTestResults() {
    return runner.getResults(yui_instance.Test.Format.JSON);
}

Что касается селеновой стороны, мы использовали параметризованный тест. Мы запускаем наши тесты как в IE, так и в FireFox в методе data, анализируя результаты теста в виде списка массивов объектов, каждый массив которого содержит имя браузера, имя файла теста, имя теста, результат (пройти, потерпеть неудачу или игнорировать) и сообщение.

Фактический тест только подтверждает результат теста. Если он не равен «pass», он не проходит тест с сообщением, возвращенным из результата теста YUI.

    @Parameters
public static List<Object[]> data() throws Exception {
    yui_test_codebase = "file:///c://myapppath/yui/tests";

    List<Object[]> testResults = new ArrayList<Object[]>();

    pageNames = new ArrayList<String>();
    pageNames.add("yuiTest1.html");
    pageNames.add("yuiTest2.html");

    testResults.addAll(runJSTestsInBrowser(IE_NOPROXY));
    testResults.addAll(runJSTestsInBrowser(FIREFOX));
    return testResults;
}

/**
 * Creates a selenium instance for the given browser, and runs each
 * YUI Test page.
 * 
 * @param aBrowser
 * @return
 */
private static List<Object[]> runJSTestsInBrowser(Browser aBrowser) {
    String yui_test_codebase = "file:///c://myapppath/yui/tests/";
    String browser_bot = "this.browserbot.getCurrentWindow()"
    List<Object[]> testResults = new ArrayList<Object[]>();
    selenium = new DefaultSelenium(APPLICATION_SERVER, REMOTE_CONTROL_PORT, aBrowser.getCommand(), yui_test_codebase);
    try {
        selenium.start();

        /*
         * Run the test here
         */
        for (String page_name : pageNames) {
            selenium.open(yui_test_codebase + page_name);
            //Wait for the YAHOO instance to be available
            selenium.waitForCondition(browser_bot + ".yui_instance != undefined", "10000");
            selenium.getEval("dom=runYUITestSuite(" + browser_bot + ")");

            //Output from the tests is not available until 
            //the YAHOO.Test.Runner is done running the suite
            selenium.waitForCondition("!" + browser_bot + ".isRunning()", "10000");
            String output = selenium.getEval("dom=getYUITestResults(" + browser_bot + ")");

            JSONObject results = JSONObject.fromObject(output);
            JSONObject test_case = results.getJSONObject("jsTestCase");
            JSONArray testCasePropertyNames = test_case.names();
            Iterator itr = testCasePropertyNames.iterator();

            /*
             * From the output, build an array with the following:
             *  Test file
             *  Test name
             *  status (result)
             *  message
             */
            while(itr.hasNext()) {
                String name = (String)itr.next();
                if(name.startsWith("test")) {
                    JSONObject testResult = test_case.getJSONObject(name);
                    String test_name = testResult.getString("name");
                    String test_result = testResult.getString("result");
                    String test_message = testResult.getString("message");
                    Object[] testResultObject = {aBrowser.getCommand(), page_name, test_name, test_result, test_message};
                    testResults.add(testResultObject);
                }
            }

        }
    } finally {
        //if an exception is thrown, this will guarantee that the selenium instance
        //is shut down properly
        selenium.stop();
        selenium = null;
    }
    return testResults;
}
/**
 * Inspects each test result and fails if the testResult was not "pass"
 */
@Test
public void inspectTestResults() {
    if(!this.testResult.equalsIgnoreCase("pass")) {
        fail(String.format(MESSAGE_FORMAT, this.browser, this.pageName, this.testName, this.message));
    }
}

Надеюсь, это полезно.

2 голосов
/ 18 сентября 2008

Просмотр YUITest

1 голос
/ 18 марта 2014

Я посмотрел дату вашего вопроса и тогда было несколько хороших JS-тестирований lib / framework. Сегодня вы можете найти гораздо больше и в разных сферах, таких как TDD, BDD, Assetion и с / без поддержки бегунов.

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

1 голос
/ 27 марта 2012

Я опубликовал небольшую библиотеку для проверки зависящих от браузера тестов JavaScript без необходимости использования браузера. Это модуль node.js, который использует zombie.js для загрузки тестовой страницы и проверки результатов. Я написал об этом в своем блоге . Вот как выглядит автоматизация:

var browsertest = require('../browsertest.js').browsertest;

describe('browser tests', function () {

it('should properly report the result of a mocha test page', function (done) {
    browsertest({
        url: "file:///home/liam/work/browser-js-testing/tests.html",
        callback: function() { 
            done();
        }
    });
});

});
1 голос
/ 16 января 2012

В проекте, над которым я работаю, используется Js-Test-Driver хостинг Jasmine в Chrome 10 с Jasmine-JSTD-Adapter , включая использование Покрытие кода тесты, включенные в JS-Test-Driver. Несмотря на то, что каждый раз, когда мы меняем или обновляем браузеры в среде CI , возникают некоторые проблемы, тесты с жасмином работают довольно гладко, с незначительными проблемами с асинхронными тестами, но, насколько я знаю, их можно обойти. используя Жасминовые Часы, но у меня еще не было возможности их исправить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...