javascript
使用Jasmine,Spock和Nashorn测试JVM服务器端JavaScript
JavaScript使用不僅限于瀏覽器中的客戶端代碼或NodeJS支持的服務器端代碼。 許多基于JVM的項目都將其用作內部腳本語言。 測試這種功能既不簡單也不標準。 在本文中,我打算演示一種使用成熟的工具(例如Jasmine , Spock和Nashorn在服務器端JVM環境中測試JavaScript的方法。
與客戶端編碼相比,在JVM應用程序內部使用JavaScript作為腳本引擎有很大的不同。 不幸的是,如今沒有用于測試它的工業標準工具。
關于Internet中現有的方法,我想強調以下缺點:
- 缺乏與構建和持續集成工具(Maven,Gradle,Jenkins等)的集成
- 與IDE的合作不足
- 無法運行單個套件或通過IDE進行測試
- 與瀏覽器環境緊密耦合
- 無法使用自定義的JavaScript執行程序
據我所知,大多數項目通過調用JS引擎運行器,將被測腳本傳遞給它并通過檢查腳本執行后對引擎或模擬的副作用進行斷言來測試其嵌入式業務腳本。
這些方法通常具有類似的缺點:
- 難以對JS代碼進行存根或模擬,通常會導致對JS prototype黑客攻擊
- 腳本的模擬環境需要過多的編排
- 難以將測試組織到套件中并報告測試執行錯誤
- 以前的原因為特定項目創建了自定義測試套件框架
- 不利用現有JavaScript測試工具和框架
因此,在JVM項目中需要舒適的嵌入式JavaScript測試的推動下,我創建了此示例設置。 為了實現我們的目標,將使用下一個工具。
- Jasmine是最著名JavaScript TDD / BDD工具之一
- Spock是由Junit和Groovy支持的JVM的出色測試框架
- Nashorn是JDK8中引入的現代腳本引擎
定制JavaScript運行器(基于Nashorn)
在非瀏覽器JS環境中不需要遵循標準,因此開發人員通常使用自定義函數,內置變量等擴展腳本引擎。對于生產和測試目的,使用完全相同的運行程序極為重要。
讓我們考慮一下,我們有這樣的自定義運行器,接受腳本名稱和預定義變量的映射作為參數并返回執行腳本的結果值。
JavaScriptRunner.java
public class JavaScriptRunner {public static Object run(String script, Map<String, Object> params) throws Exception {ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByName("nashorn");engine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(params);return engine.eval(new InputStreamReader(JavaScriptRunner.class.getResourceAsStream(script))); (1)} }| 1個 | 在類路徑中搜索腳本源。 |
茉莉花的設置
要開始使用Jasmine框架,我們需要:
- 下載Jasmine并將其解壓縮到項目資源目錄中的/jasmine/jasmine-2.1.2文件夾中
- 自定義引導腳本,因為Jasmine不支持基于JVM的平臺
jasmine2-bootstrap.js
var loadFromClassPath = function(path) { (1)load(Java.type("ua.eshepelyuk.blog.nashorn.Jasmine2Specification").class.getResource(path).toExternalForm()); };var window = this;loadFromClassPath("/jasmine/jasmine-2.1.2/jasmine.js"); loadFromClassPath("/jasmine/jasmine2-html-stub.js"); (2) loadFromClassPath("/jasmine/jasmine-2.1.2/boot.js"); load({script: __jasmineSpec__, name: __jasmineSpecName__}); (3)onload(); (4)jsApiReporter.specs(); (5)| 1個 | helper函數從類路徑位置解析腳本路徑。 |
| 2 | Nashorn專用代碼可在非瀏覽器環境中調整Jasmine 。 不屬于Jasmine發行。 |
| 3 | 加載測試套件源代碼,有關詳細信息,請參見下一部分。 |
| 4 | 偽造瀏覽器load事件,應觸發測試套件執行。 |
| 5 | 該值將作為腳本結果返回。 |
將Jasmine報告轉換為Spock測試
使用Jasmine JS執行程序和引導腳本,我們可以創建JUnit測試以遍歷套件結果并檢查是否全部成功。 但是,了解哪個特定測試失敗以及失敗的原因將成為一場噩夢。 我們真正想要擁有的是將每個Jasmine規范表示為JUnit測試的功能,因此任何Java工具都可以拾取并檢查結果。 這就是為什么Spock可以解決問題的原因,它的數據驅動測試允許開發人員聲明輸入數據列表,并針對該數據集的每個項目創建并執行新測試。 這與Junit 參數化測試非常相似,但功能更強大。
因此,想法是將運行引導腳本后獲得的Jasmine測試套件結果視為輸入數據數組,其每一項都將傳遞給Spock測試。 然后測試本身將提供斷言以正確報告成功和失敗的測試,即斷言應檢查Jasmine規范的狀態。
- 如果狀態為pending或passed ,則表示規范被忽略或成功
- 否則, Spock測試應該拋出斷言錯誤,并用Jasmine報告的失敗消息填充斷言異常
Jasmine2Specification.groovy
abstract class Jasmine2Specification extends Specification {@Shared def jasmineResultsdef setupSpec() {def scriptParams = ["__jasmineSpec__" : getMetaClass().getMetaProperty("SPEC").getProperty(null), (1)"__jasmineSpecName__": "${this.class.simpleName}.groovy"]jasmineResults = JavaScriptRunner.run("/jasmine/jasmine2-bootstrap.js", scriptParams) (2)}def isPassed(def specRes) {specRes.status == "passed" || specRes.status == "pending"}def specErrorMsg(def specResult) {specResult.failedExpectations.collect {it.value}.collect {it.stack}.join("\n\n\n")}@Unroll def '#specName'() {expect:assert isPassed(item), specErrorMsg(item) (3)where:item << jasmineResults.collect { it.value }specName = (item.status != "pending" ? item.fullName : "IGNORED: $item.fullName") (4)} }| 1個 | 將Jasmine套件的源代碼公開為jasmineSpec變量,可讓JS執行器訪問。 |
| 2 | Jasmine套件的實際執行。 |
| 3 | 對于每個套件結果,我們assert要么成功,要么在失敗時使用Jasmine發起的消息引發斷言錯誤。 |
| 4 | 附加的數據提供程序變量以突出顯示被忽略的測試。 |
完整的例子
讓我們為簡單JavaScript函數創建測試套件。
mathUtils.js
var add = function add(a, b) {return a + b; };使用上一步中的基類,我們可以創建包含JavaScript測試的Spock套件。 為了演示我們解決方案的所有可能性,我們將創建成功,失敗和被忽略的測試。
MathUtilsTest.groovy
class MathUtilsTest extends Jasmine2Specification {static def SPEC = """ (1) loadFromClassPath("/js/mathUtils.js"); (2) describe("suite 1", function() {it("should pass", function() {expect(add(1, 2)).toBe(3);});it("should fail", function() {expect(add(1, 2)).toBe(3);expect(add(1, 2)).toBe(0);});xit("should be ignored", function() {expect(add(1, 2)).toBe(3);}); }) """ }| 1個 | Jasmine套件的實際代碼表示為String變量。 |
| 2 | 使用從jasmine-bootstrap.js繼承的功能加載受測模塊。 |
圖1. IntelliJ IDEA的測試結果
IntelliJ Idea語言注入
盡管此微框架可以在所有IDE中使用,但由于其語言注入 ,它的最方便用法將在IntelliJ IDEA中 。 該功能允許將任意語言嵌入到以其他編程語言創建的文件中。 因此,我們可以將JavaScript代碼塊嵌入到用Groovy編寫的Spock規范中。
圖2.語言注入
解決方案的優缺點
優點
- 使用兩種語言的行業標準測試工具
- 與構建工具和持續集成工具的無縫集成
- 從IDE運行單個套件的能力
- 借助Jasmine的突出功能,可以從特定套件運行單個測試
缺點
- 在測試異常的情況下,沒有干凈的方法來檢測特定的源代碼行
- 一點面向IntelliJ IDEA的設置
聚苯乙烯
在此示例項目中,我使用了JDK8的現代Nashorn引擎。 但實際上對此沒有限制。 同樣的方法已成功應用于使用較舊Rhino引擎的項目。 再說一次, Jasmine只是我的個人喜好。 隨著其他工作代碼的調整,可以利用Mocha , QUnit等。
- 完整的項目代碼可在My GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/12/testing-jvm-server-side-javascript-with-jasmine-spock-and-nashorn.html
總結
以上是生活随笔為你收集整理的使用Jasmine,Spock和Nashorn测试JVM服务器端JavaScript的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何轻松配置上网行为管理功能路由器如何设
- 下一篇: 离线电脑系统补丁(win7离线补丁)