2008-09-18 108 views
58

我试图将一些JavaScript单元测试合并到我的自动构建过程中。目前JSUnit可以很好的与JUnit协同工作,但它似乎被遗弃,并且对AJAX,调试和超时缺乏良好的支持。使用JavaScript进行自动单元测试

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

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

+1

相关问题: http://stackoverflow.com/questions/300855/looking-for-a-better-javascript-unit-test-tool – 2010-05-12 21:05:29

回答

19

有很多JavaScript的单元测试框架在那里(JSUnit的,Scriptaculous的,...),但JSUnit的是唯一一个我知道,可与自动构建中。

如果你正在做'真正的'单元测试,你不应该需要AJAX支持。例如,如果您使用的是RPC Ajax框架,如DWR,你可以随便写一个模拟功能:

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

是的,JSUnit的不处理超时:Simulating Time in jsUnit Tests

0

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

CrossCheck尝试模仿浏览器,包括XMLHttpRequest的模拟实现和超时/间隔。

虽然它当前不处理从网页加载JavaScript。您必须指定要加载和测试的JavaScript文件。如果你将所有的JS与你的HTML分开,它可能适用于你。

24

我刚刚开始在我正在开发的一个新项目上开发Javascript TDD。我目前的计划是使用qunit来进行单元测试。开发测试可以通过在浏览器中刷新测试页面来运行。

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

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

我目前正在设置这个。一旦我将设置敲定出来,我会更新这个答案并提供更详细的信息。


测试工具:

+0

是的,请分享它。谢谢 – melaos 2009-02-10 07:49:43

+0

你有没有得到这个设置?它是如何去的? – 2010-08-16 04:34:21

13

Im的js-test-driver

一个大风扇它运作良好,在CI环境,能够捕捉到实际的浏览器的跨浏览器测试。

2

我同意jsunit在藤上死去。我们刚完成使用YUI Test进行替换。

与使用qUnit的示例类似,我们使用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); 
} 

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

实际测试只声明测试结果。如果它不等于“通过”,则它将通过从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)); 
    } 
} 

我希望这是有帮助的。

4

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

(哈德森通过shell运行Java,运行Envjs,运行JasmineBDD。)

我还没有得到它玩好一个大图书馆的是,虽然像原型。

1

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

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

我它使用的单元测试的jQuery插件,objx代码,自定义OO JavaScript和它的作品的一切不加修改。

1

我正在使用项目Js-Test-DriverJasmine-JSTD-Adapter在Chrome 10托管Jasmine包括利用的Code Coverage测试包括在JS-试车手。虽然每次我们在CI environment上更改或更新浏览器时都会遇到一些问题,但茉莉花测试运行得非常顺利,只有少数问题与ansynchronous测试有关,但据我所知,这些可以用茉莉花时钟解决,但我没有' t有机会修补它们。

1

我已经发布了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(); 
     } 
    }); 
}); 

}); 
1

我枕着你的问题的日期和当时有几个不错的JS测试的lib /框架。 今天,你可以找到更多的和不同的焦点,如TDD,BDD,评估和有/没有赛跑者的支持。

有在这场比赛中像摩卡,柴,QUnit,茉莉花等.. 很多球员可以找到this博客关于JS /手机/网络测试的一些详细信息...