60

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

有没有人有幸(使用Ant)自动化单元测试库,例如YUI测试、jQuery 的QUnitjQUnit

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

4

14 回答 14

24

我正要开始在我正在做的一个新项目上做 JavaScript TDD 。我目前的计划是使用QUnit进行单元测试。在开发测试时,只需在浏览器中刷新测试页面即可运行。

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

我还将使用JSCoverage来获取测试的代码覆盖率分析。这也将通过 Selenium 实现自动化。

我目前正在设置这个。设置完成后,我将使用更准确的详细信息更新此答案。


测试工具:

于 2008-09-18T20:44:13.803 回答
20

那里有许多 JavaScript 单元测试框架(JSUnit、scriptaculous 等),但 JSUnit 是我所知道的唯一一个可以用于自动构建的框架。

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

   函数模拟函数(someArg,回调){
      变量结果 = ...; //一些处理
      设置超时(
函数(){回调(结果);}, 300 // 一些虚假的延迟 ); }

是的,JSUnit 确实处理超时:Simulating Time in JSUnit Tests

于 2008-09-18T19:51:49.983 回答
13

我是js-test-driver的忠实粉丝。

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

于 2009-11-03T16:15:27.023 回答
4

我最近阅读了 Bruno 的一篇文章,使用 JSUnit 并在此基础上创建了一个 JsMock 框架……非常有趣。我正在考虑使用他的工作来开始对我的 JavaScript 代码进行单元测试。

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

于 2008-09-26T12:35:18.167 回答
4

我刚刚让 Hudson CI 运行 JasmineBDD(无头),至少对于纯 JavaScript 单元测试。

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

不过,我还没有让它与一个大图书馆很好地配合,比如原型。

于 2010-10-19T11:39:31.597 回答
2

查看YUITest

于 2008-09-18T19:36:52.780 回答
2

我同意 JSUnit 有点垂死挣扎。我们刚刚用 YUI 测试完成了替换它。

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

首先,我们有一个包含在所有测试 HTML 文件中的基本 JavaScript 文件。这处理设置 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);
}

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

实际测试只是断言测试结果。如果它不等于“通过”,那么它会通过从 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));
    }
}
于 2009-12-11T22:33:22.130 回答
1

有一个新项目可让您在 Java 环境(如 Ant)中运行QUnit测试,因此您可以将客户端测试套件与其他单元测试完全集成。

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

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

于 2010-12-01T10:42:50.343 回答
1

我正在处理的项目使用Js-Test-Driver在 Chrome 10 上托管Jasmine和Jasmine-JSTD-Adapter,包括使用JS-Test-Driver 中包含的代码覆盖率测试。

虽然每次我们在CI 环境中更改或更新浏览器时都会出现一些问题,但 Jasmine 测试运行得非常顺利,只有异步测试的小问题,但据我所知,这些可以使用 Jasmine Clock 解决,但我还没有机会修补它们。

于 2012-01-16T11:03:42.697 回答
1

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

});
于 2012-03-27T09:07:58.507 回答
1

我查看了您的问题日期,当时有一些很好的 JavaScript 测试库和框架。

今天,您可以找到更多不同的焦点,例如TDDBDD、Assetion 以及有/无跑步者支持。

这个游戏有很多玩家,像MochaChaiQUnitJasmine等......

您可以在博客中找到有关 JavaScript、移动和 Web 测试的更多信息...

于 2014-03-18T08:03:09.130 回答
0

另一个可以与 Ant 一起运行的 JavaScript 测试框架是CrossCheck。在项目的构建文件中有一个通过 Ant 运行 CrossCheck 的示例。

CrossCheck 尝试模拟浏览器,但成功有限,包括XMLHttpRequest和超时/间隔的模拟样式实现。

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

于 2008-09-18T20:30:14.307 回答
0

我编写了一个 Ant 任务,它使用PhantomJS(一个无头WebKit浏览器)在 Ant 构建过程中运行 QUnit HTML 测试文件。如果任何测试失败,它也可能导致构建失败。

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

于 2012-06-05T19:34:09.587 回答
0

这是对几个测试工具的一个很好的评价。

用于 TDD 的 JavaScript 单元测试工具

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

于 2013-07-11T15:17:49.323 回答