【问题标题】:Automated unit testing with JavaScript使用 JavaScript 进行自动化单元测试
【发布时间】:2010-09-10 21:32:24
【问题描述】:

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

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

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

【问题讨论】:

标签: javascript jquery unit-testing ant automation


【解决方案1】:

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

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

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

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


测试工具:

【讨论】:

  • 你设置过这个吗?进展如何?
  • 我确实设置了这个,但使用的技术略有不同。我使用 JS 测试驱动程序在每个浏览器(而不是 Selenium)中运行单元测试,使用 QUnit 适配器 (code.google.com/p/js-test-driver/wiki/QUnitAdapter)。我现在的雇主的另一个我正在使用 Jasmine 测试框架,并在 Jasmine Node (github.com/mhevery/jasmine-node) 中运行测试,这避免了使用浏览器的延迟。我使用我自己的小 ruby​​ 项目 (github.com/karl/loris) 对每个更改运行测试。
  • 几乎是硒的最佳用途。伙计,我在这件事上浪费了很多时间。嘟嘟嘟嘟嘟……
  • 嗨@Karl。我还发现 qunit 是一个有用的工具,但不知道要测试什么。我有一个用 javascript 编写的带有组合、动画的游戏逻辑。你能帮我一些信息吗?谢谢。
【解决方案2】:

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

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

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 我喜欢它,因为它集成了 CI,但我认为它最大的优点是它可以与 YUITest 和 QUnit 一起使用!
    【解决方案4】:

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

    Mock JavaScript or How to unit test JavaScript outside the Browser environment

    【讨论】:

      【解决方案5】:

      我只是 got Hudson CI to run JasmineBDD(无头),至少对于纯 JavaScript 单元测试而言。

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

      不过,我还没有让它很好地与大型库配合使用,比如原型。

      【讨论】:

        【解决方案6】:

        查看YUITest

        【讨论】:

          【解决方案7】:

          我同意 JSUnit 有点垂死挣扎。我们刚刚用 YUI Test 替换了它。

          与使用 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));
              }
          }
          

          【讨论】:

            【解决方案8】:

            我正在处理的项目使用 Js-Test-Driver 在 Chrome 10 上托管 JasmineJasmine-JSTD-Adapter,包括使用 JS-Test-Driver 中包含的 code coverage 测试。

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

            【讨论】:

              【解决方案9】:

              我已经发布了a little library,用于验证依赖于浏览器的 JavaScript 测试,而无需使用浏览器。它是一个 Node.js 模块,它使用zombie.js 加载测试页面并检查结果。我已经写了on my blog。下面是自动化的样子:

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

              【讨论】:

                【解决方案10】:

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

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

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

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

                【讨论】:

                • 什么是“资产”?
                【解决方案11】:

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

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

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

                【讨论】:

                  【解决方案12】:

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

                  JavaScript unit test tools for TDD

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

                  【讨论】:

                    【解决方案13】:

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

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

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

                    【讨论】:

                      【解决方案14】:

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

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

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-08-29
                        • 2014-04-30
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2023-03-04
                        相关资源
                        最近更新 更多