2008-09-18 114 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 /手機/網絡測試的一些詳細信息...