简体   繁体   English

使用 JavaScript 进行自动化单元测试

[英]Automated unit testing with JavaScript

I'm trying to incorporate some JavaScript unit testing into my automated build process.我正在尝试将一些 JavaScript 单元测试合并到我的自动构建过程中。 Currently JSUnit works well with JUnit, but it seems to be abandonware and lacks good support for Ajax, debugging, and timeouts.目前 JSUnit 可以很好地与 JUnit 配合使用,但它似乎是废弃软件,并且缺乏对 Ajax、调试和超时的良好支持。

Has anyone had any luck automating (with Ant ) a unit testing library such as YUI test, jQuery's QUnit , or jQUnit ?有没有人有幸自动化(使用Ant )单元测试库,例如YUI测试、jQuery 的QUnitjQUnit

Note: I use a custom built Ajax library, so the problem with Dojo's DOH is that it requires you to use their own Ajax function calls and event handlers to work with any Ajax unit testing.注意:我使用自定义构建的 Ajax 库,所以 Dojo 的 DOH 的问题在于它要求您使用他们自己的 Ajax 函数调用和事件处理程序来处理任何 Ajax 单元测试。

I'm just about to start doing JavaScript TDD on a new project I am working on.我即将开始在我正在处理的一个新项目上执行 JavaScript TDD My current plan is to use QUnit to do the unit testing.我目前的计划是使用QUnit进行单元测试。 While developing the tests can be run by simply refreshing the test page in a browser.在开发测试时,只需在浏览器中刷新测试页面即可运行。

For continuous integration (and ensuring the tests run in all browsers), I will use Selenium to automatically load the test harness in each browser, and read the result.对于持续集成(并确保测试在所有浏览器中运行),我将使用Selenium在每个浏览器中自动加载测试工具,并读取结果。 These tests will be run on every checkin to source control.这些测试将在每次签入源代码管理时运行。

I am also going to use JSCoverage to get code coverage analysis of the tests.我还将使用JSCoverage来获取测试的代码覆盖率分析。 This will also be automated with Selenium.这也将通过 Selenium 自动化。

I'm currently in the middle of setting this up.我目前正在设置它。 I'll update this answer with more exact details once I have the setup hammered out.一旦我敲定了设置,我将用更准确的细节更新这个答案。


Testing tools:测试工具:

There are many JavaScript unit test framework out there (JSUnit, scriptaculous, ...), but JSUnit is the only one I know that may be used with an automated build.有许多 JavaScript 单元测试框架(JSUnit、scriptaculous 等),但我知道 JSUnit 是唯一一个可以与自动化构建一起使用的框架。

If you are doing 'true' unit test you should not need AJAX support.如果您正在进行“真正的”单元测试,则不需要 AJAX 支持。 For example, if you are using an RPC Ajax framework such as DWR, you can easily write a mock function:例如,如果您使用 DWR 等RPC Ajax 框架,则可以轻松编写一个模拟函数:

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

And yes, JSUnit does handle timeouts: Simulating Time in JSUnit Tests是的,JSUnit 确实处理超时: 在 JSUnit 测试中模拟时间

I'm a big fan of js-test-driver .我是js-test-driver 的忠实粉丝。

It works well in a CI environment and is able to capture actual browsers for cross-browser testing.它在CI环境中运行良好,能够捕获实际浏览器进行跨浏览器测试。

I recently read an article by Bruno using JSUnit and creating a JsMock framework on top of that... very interesting.我最近阅读了 Bruno 的一篇文章,使用 JSUnit 并在此基础上创建了一个 JsMock 框架……非常有趣。 I'm thinking of using his work to start unit testing my JavaScript code.我正在考虑使用他的工作来开始对我的 JavaScript 代码进行单元测试。

Mock JavaScript or How to unit test JavaScript outside the Browser environment 模拟 JavaScript 或如何在浏览器环境之外对 JavaScript 进行单元测试

I just got Hudson CI to run JasmineBDD (headless), at least for pure JavaScript unit testing.我刚刚让 Hudson CI 运行 JasmineBDD (无头),至少用于纯 JavaScript 单元测试。

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

I haven't got it to play nice with a big library yet, though, like prototype.不过,我还没有让它在一个大图书馆里玩得很好,比如原型。

I am in agreement that JSUnit is kind of dying on the vine.我同意 JSUnit 正在濒临死亡。 We just finished up replacing it with YUI Test.我们刚刚用 YUI Test 替换了它。

Similar to the example using qUnit, we are running the tests using Selenium .与使用 qUnit 的示例类似,我们使用Selenium运行测试。 We are running this test independently from our other Selenium tests simply because it does not have the dependencies that the normal UI regression tests have (eg deploying the application to a server).我们独立于其他 Selenium 测试运行此测试,仅仅是因为它没有正常 UI 回归测试所具有的依赖项(例如,将应用程序部署到服务器)。

To start out, we have a base JavaScript file that is included in all of our test HTML files.首先,我们有一个包含在所有测试 HTML 文件中的基本 JavaScript 文件。 This handles setting up the YUI instance, the test runner, the YUI.Test.Suite object as well as the Test.Case.这将处理设置 YUI 实例、测试运行程序、YUI.Test.Suite 对象以及 Test.Case。 It has methods that can be accessed via Selenium to run the test suite, check to see if the test runner is still running (results are not available until after it's done), and get the test results (we chose JSON format):它具有可以通过 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);
}

As for the Selenium side of things, we used a parameterized test.至于 Selenium 方面,我们使用了参数化测试。 We run our tests in both Internet Explorer and Firefox in the data method, parsing the test results into a list of Object arrays with each array containing the browser name, the test file name, the test name, the result (pass, fail or ignore) and the message.我们在 Internet Explorer 和 Firefox 中的 data 方法中运行我们的测试,将测试结果解析为一个 Object 数组列表,每个数组包含浏览器名称、测试文件名、测试名称、结果(通过、失败或忽略) ) 和消息。

The actual test just asserts the test result.实际测试只是断言测试结果。 If it is not equal to "pass" then it fails the test with the message returned from the YUI Test result.如果它不等于“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));
    }
}

查看YUITest

I looked on your question date and back then there were a few good JavaScript testing libraries and frameworks.我查看了您的问题日期,当时有一些很好的 JavaScript 测试库和框架。

Today you can find much more and in different focus like TDD , BDD , Assetion and with/without runners support.今天,您可以找到更多不同的焦点,例如TDDBDD 、 Assetion 以及有/没有跑步者支持。

There are many players in this game, like Mocha , Chai , QUnit , Jasmine , etc...这个游戏有很多玩家,比如MochaChaiQUnitJasmine等等……

You can find some more information in this blog about JavaScript, mobile, and web testing...您可以在博客中找到有关 JavaScript、移动和 Web 测试的更多信息...

There's a new project that lets you run QUnit tests in a Java environment (like Ant) so you can fully integrate your client-side test suite with your other unit tests.有一个新项目可以让您在 Java 环境(如 Ant)中运行QUnit测试,以便您可以将客户端测试套件与其他单元测试完全集成。

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

I've used it to unit test jQuery plugins, objx code, custom OO JavaScript and it works for everything without modification.我用它来对 jQuery 插件、 objx代码、自定义 OO JavaScript 进行单元测试,它无需修改即可用于所有内容。

The project I'm working on uses Js-Test-Driver hosting Jasmine on Chrome 10 with Jasmine-JSTD-Adapter including making use of code coverage tests included in JS-Test-Driver.我正在从事的项目使用Js-Test-Driver在 Chrome 10 上托管JasmineJasmine-JSTD-Adapter,包括利用 JS-Test-Driver 中包含的代码覆盖测试。

While there are some problems each time we change or update browsers on the CI environment the Jasmine tests are running pretty smoothly with only minor issues with ansynchronous tests, but as far as I'm aware these can be worked around using Jasmine Clock, but I haven't had a chance to patch them yet.虽然每次我们在CI 环境中更改或更新浏览器时都会出现一些问题,但 Jasmine 测试运行得非常顺利,只有异步测试的小问题,但据我所知,这些可以使用 Jasmine Clock 解决,但我还没有机会修补它们。

I've published a little library for verifying browser-dependent JavaScript tests without having to use a browser.我发布了一个小库,用于验证依赖于浏览器的 JavaScript 测试而无需使用浏览器。 It is a Node.js module that uses zombie.js to load the test page and inspect the results.它是一个Node.js 模块,它使用zombie.js 加载测试页面并检查结果。 I've wrote about it on my blog .我已经在我的博客上写过它。 Here is what the automation looks like:这是自动化的样子:

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();
            }
        });
    });

});

I've written an Ant task which uses PhantomJS , a headless WebKit browser, to run QUnit HTML test files within an Ant build process.我编写了一个 Ant 任务,它使用PhantomJS (一个无头WebKit浏览器)在 Ant 构建过程中运行 QUnit HTML 测试文件。 It can also fail the build if any tests fail.如果任何测试失败,它也可能使构建失败。

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

This is a good evaluation of several testing tools.这是对几个测试工具的一个很好的评价。

JavaScript unit test tools for TDD TDD 的 JavaScript 单元测试工具

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

Another JavaScript testing framework that can be run with Ant is CrossCheck .另一个可以与 Ant 一起运行的 JavaScript 测试框架是CrossCheck There's an example of running CrossCheck via Ant in the build file for the project.在项目的构建文件中有一个通过 Ant 运行 CrossCheck 的示例。

CrossCheck attempts, with limited success, to emulate a browser, including mock-style implementations of XMLHttpRequest and timeout/interval. CrossCheck 尝试模拟浏览器,包括XMLHttpRequest和超时/间隔的模拟风格实现,但取得了有限的成功。

It does not currently handle loading JavaScript from a web page, though.不过,它目前不处理从网页加载 JavaScript。 You have to specify the JavaScript files that you want to load and test.您必须指定要加载和测试的 JavaScript 文件。 If you keep all of your JavaScript code separated from your HTML, it might work for you.如果您将所有 JavaScript 代码与 HTML 分开,它可能对您有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM