关于jquery:使用JavaScript进行自动单元测试

关于jquery:使用JavaScript进行自动单元测试

Automated Unit Testing with JavaScript

我正在尝试将一些JavaScript单元测试合并到我的自动构建过程中。 当前,JSUnit与JUnit可以很好地协作,但是它似乎已经被弃用,并且缺乏对AJAX,调试和超时的良好支持。

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

注意:我使用定制的AJAX库,所以Dojo的DOH的问题在于它要求您使用自己的AJAX函数调用和事件处理程序来进行任何AJAX单元测试。


我即将开始在我正在从事的新项目中执行Javascript TDD。我当前的计划是使用qunit进行单元测试。在开发测试时,只需在浏览器中刷新测试页面即可运行测试。

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

我还将使用JSCoverage进行测试的代码覆盖率分析。 Selenium也将自动执行此操作。

我目前正在进行此设置。一旦设置完成,我将使用更准确的详细信息更新此答案。

测试工具:

  • qunit
  • JSCoverage

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

如果您要进行"真实"的单元测试,则不需要AJAX支持。例如,如果您使用的是诸如DWR之类的RPC ajax框架,则可以轻松编写一个模拟函数:

1
2
3
4
5
6
7
   function mockFunction(someArg, callback) {
      var result = ...; // some treatments  
      setTimeout(
        function() { callback(result); },
        300  // some fake latency
      );
    }

是的,JsUnit可以处理超时:在jsUnit测试中模拟时间


我是js-test-driver的忠实拥护者

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


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

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

不过,我还没有像大型原型库那样在大型图书馆中表现出色。


最近,我读了Bruno的文章,该文章使用JsUnit并在此之上创建了一个JsMock框架...非常有趣。我正在考虑使用他的工作来开始对Javascript代码进行单元测试。

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


我同意jsunit快死了。我们刚刚完成了将其替换为YUI测试。

与使用qUnit的示例相似,我们使用Selenium运行测试。我们独立于其他硒测试而独立运行此测试,只是因为它不具有普通UI回归测试所具有的依赖性(例如,将应用程序部署到服务器)。

首先,我们在所有测试html文件中都包含一个基本的javascript文件。这负责设置YUI实例,测试运行器,YUI.Test.Suite对象以及Test.Case。它具有可以通过Selenium访问的方法来运行测试套件,检查测试运行程序是否仍在运行(结果在完成后才可用),并获取测试结果(我们选择了JSON格式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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中运行测试,将测试结果解析为Object数组列表,每个数组包含浏览器名称,测试文件名称,测试名称,结果(通过,失败或忽略)和消息。

实际测试只是断言测试结果。如果不等于"通过",则它将通过YUI测试结果返回的消息使测试失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    @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));
    }
}

我希望这是有帮助的。


看看YUITest


我查看了您的问题日期,然后发现有一些不错的JS测试lib / framework。
今天,您可以找到更多的内容,并且关注的重点不同,例如TDD,BDD,Assetion,以及是否有跑步者支持。

此游戏中有很多玩家,例如摩卡,柴,QUnit,茉莉花等。
您可以在此博客中找到有关JS / Mobile / web测试的更多信息...


我已经发布了一个小库,无需使用浏览器即可验证与浏览器相关的JavaScript测试。这是一个使用zombie.js加载测试页并检查结果的node.js模块。我已经在我的博客上写过。这是自动化的样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();
        }
    });
});

});

我正在研究的项目使用带有Jasmine-JSTD-Adapter的Chrome 10上的Jasmine托管Js-Test-Driver,包括利用JS-Test-Driver中包含的Code Coverage测试。尽管每次我们在CI环境中更改或更新浏览器时都会遇到一些问题,但是茉莉花测试运行相当顺利,而异步测试只有很小的问题,但是据我所知,使用茉莉花时钟可以解决这些问题,但是我还没有还没有机会修补它们。


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

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

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


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

TDD的JavaScript单元测试工具

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


我编写了一个Ant任务,该任务使用无头Webkit浏览器Phantom JS在Ant构建过程中运行QUnit html测试文件。如果任何测试失败,它也会使构建失败。

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


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

CrossCheck尝试模拟浏览器,但收效甚微,其中包括XMLHttpRequest和超时/间隔的模拟样式实现。

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


推荐阅读