我正在尝试将一些 JavaScript 单元测试合并到我的自动化构建过程中。目前,JSUnit 与 JUnit 配合得很好,但它似乎是废弃软件,并且缺乏对 AJAX、调试和超时的良好支持。

有没有人有幸自动化(使用 ANT)单元测试库,例如 YUI test、JQuery 的 QUnit 或 jQUnit(http://code.google.com/p/jqunit/)?

笔记:我使用自定义构建的 AJAX 库,因此 Dojo 的 DOH 的问题是它要求您使用自己的 AJAX 函数调用和事件处理程序来处理任何 AJAX 单元测试。

有帮助吗?

解决方案

有许多 javascript 单元测试框架(jsUnit、scriptaculous 等),但 jsUnit 是我所知道的唯一一个可以与自动构建一起使用的框架。

如果您正在进行“真正的”单元测试,则不需要 AJAX 支持。例如,如果您使用 DWR 等 RPC ajax 框架,则可以轻松编写模拟函数:

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

是的,JsUnit 确实处理超时: 模拟 jsUnit 测试中的时间

其他提示

我正准备开始在我正在从事的一个新项目中使用 Javascript TDD。我目前的计划是使用 量子单位 进行单元测试。在开发时,只需在浏览器中刷新测试页面即可运行测试。

为了持续集成(并确保测试在所有浏览器中运行),我将使用 在每个浏览器中自动加载测试工具并读取结果。这些测试将在每次签入源代码管理时运行。

我也准备用 JS覆盖 获得测试的代码覆盖率分析。这也将通过 Selenium 实现自动化。

我目前正在进行设置。一旦我敲定了设置,我将用更准确的细节更新这个答案。


测试工具:

我是以下的忠实粉丝 js 测试驱动程序

它在 CI 环境中运行良好,并且能够捕获实际的浏览器以进行跨浏览器测试。

我最近阅读了 Bruno 的一篇文章,使用 JsUnit 并在此基础上创建了一个 JsMock 框架......很有意思。我正在考虑使用他的工作来开始对我的 Javascript 代码进行单元测试。

模拟 Javascript 或如何在浏览器环境之外对 Javascript 进行单元测试

我只是 让 Hudson CI 运行 JasmineBDD (无头),至少对于纯 JavaScript 单元测试来说是这样。

(Hudson 通过 shell 运行 Java,运行 Envjs,运行 JasmineBDD。)

不过,我还没有让它与大型库很好地配合,就像原型一样。

调查 YUI测试

我同意 jsunit 快要死了。我们刚刚用 YUI Test 替换了它。

与使用 qUnit 的示例类似,我们使用 Selenium 运行测试。我们独立于其他 selenium 测试运行此测试,只是因为它没有正常 UI 回归测试所具有的依赖项(例如将应用程序部署到服务器)。

首先,我们有一个基本的 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);
}

至于硒方面,我们使用了参数化测试。我们在 data 方法中在 IE 和 FireFox 中运行测试,将测试结果解析为对象数组列表,每个数组包含浏览器名称、测试文件名、测试名称、结果(通过、失败或忽略)和消息。

实际测试只是断言测试结果。如果它不等于“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));
    }
}

我希望这是有帮助的。

有一个新项目可以让你运行 量子单位 在 Java 环境(如 ant)中进行测试,以便您可以将客户端测试套件与其他单元测试完全集成。

http://qunit-test-runner.googlecode.com

我用它来对 jQuery 插件进行单元测试, 对象 代码、自定义 OO JavaScript,无需修改即可适用于所有内容。

我正在从事的项目使用 Js 测试驱动程序 托管 茉莉花 在 Chrome 10 上 Jasmine-JSTD-适配器 包括利用 代码覆盖率 JS-Test-Driver 中包含测试。虽然每次更换或更新浏览器时都会出现一些问题 CI环境 茉莉花测试运行得相当顺利,只有异步测试的小问题,但据我所知,这些可以使用茉莉花时钟来解决,但我还没有机会修补它们。

我已经发布了一个 小图书馆 用于验证依赖于浏览器的 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();
        }
    });
});

});

我查看了你的问题日期,当时有一些很好的 JS 测试库/框架。今天,您可以找到更多不同焦点的内容,例如 TDD、BDD、Assetion 以及有/没有跑步者支持。

这个游戏有很多玩家,比如 Mocha、Chai、QUnit、Jasmine 等......您可以在以下位置找到更多信息 关于 JS/移动/Web 测试的博客...

另一个可以与 Ant 一起运行的 JS 测试框架是 交叉检查. 。项目的构建文件中有一个通过 Ant 运行 CrossCheck 的示例。

CrossCheck 尝试模拟浏览器,包括 XMLHttpRequest 和超时/间隔的模拟风格实现,但取得了有限的成功。

不过,它目前不处理从网页加载 javascript。您必须指定要加载和测试的 javascript 文件。如果您将所有 JS 与 HTML 分开,它可能对您有用。

我写了一个 Ant 任务,它使用 幻影JS, ,一个无头 webkit 浏览器,用于在 Ant 构建过程中运行 QUnit html 测试文件。如果任何测试失败,构建也可能失败。

https://github.com/philmander/ant-jstestrunner

这是对几种测试工具的良好评价。

TDD 的 JavaScript 单元测试工具

我个人比较喜欢https://code.google.com/p/js-test-driver/

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top