JavaScript使用不仅限于浏览器中的客户端代码或NodeJS支持的服务器端代码。 许多基于JVM的项目都将其用作内部脚本语言。 测试这种功能既不简单也不标准。 在本文中,我打算演示一种使用成熟的工具(例如JasmineSpockNashorn在服务器端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规范的状态。

  • 如果状态为pendingpassed ,则表示规范被忽略或成功
  • 否则, 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只是我的个人喜好。 随着其他工作代码的调整,可以利用MochaQUnit等。

  • 完整的项目代码可在My GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2014/12/testing-jvm-server-side-javascript-with-jasmine-spock-and-nashorn.html

使用Jasmine,Spock和Nashorn测试JVM服务器端JavaScript相关推荐

  1. jasmine单元测试_使用Jasmine,Spock和Nashorn测试JVM服务器端JavaScript

    jasmine单元测试 JavaScript使用不仅限于浏览器中的客户端代码或NodeJS支持的服务器端代码. 许多基于JVM的项目都将其用作内部脚本语言. 测试这种功能既不简单也不标准. 在本文中, ...

  2. 如何让服务器运行js,服务器端JavaScript运行环境Node.js的依赖性管理

    众所周知,Node.js是一个基于Chrome V8引擎的服务器端JavaScript运行环境.它采用了一种事件驱动的.非阻塞式的I/O模式,运行起来既轻量级又高效.诚然,我们可以使用单个js文件,来 ...

  3. JavaScript 测试框架 ( QUnit , javascript code coverage , JSCoverage , Pavlov , Jasmine )

    changelist: -------------------------------- 1.0 如何利用QUnit来进行javascript的TDD 1.1 添加javascript code co ...

  4. spock_将Spock 1.3测试迁移到Spock 2.0

    spock 了解Spock 2.0 M1(基于JUnit 5)的期望,如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要:). 重要说明. 我绝对不建议您永久将您的真实项目迁移到S ...

  5. spock测试_将Spock 1.3测试迁移到Spock 2.0

    spock测试 了解Spock 2.0 M1(基于JUnit 5)的期望,如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要:). 重要说明 . 我绝对不建议您永久将您的现实项目迁 ...

  6. 将Spock 1.3测试迁移到Spock 2.0

    了解Spock 2.0 M1(基于JUnit 5)的期望,如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要:). 重要说明 . 我绝对不建议您永久将您的现实项目迁移到Spock ...

  7. 稳定性测试JVM内存监控

    在weblogic中配置应用启动参数,加入如下参数来生成gc日志,供测试进行JVM内存分析. -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamp ...

  8. java服务器端测试_java-在服务器端测试Spring Web Services端点?

    我正在使用Spring WS 2.0.我已经看到了端点和测试用例以测试端点. @Endpoint public class CustomerEndpoint { @ResponsePayload pu ...

  9. 使用 node.js 进行服务器端 JavaScript 编程

    node.js 是一个可以使用 JavaScript 开发服务器端应用的平台.它依托于 Google V8 JavaScript 引擎,并采用事件 I/O 的架构,可以用来创建高性能服务器.本文详细介 ...

最新文章

  1. 怎么获取请求头中的origin信息_委托单位代办汇算清缴时无法获取到我的专项附加扣除信息怎么办?...
  2. CentOS常见配置
  3. Lucene.Net无障碍学习和使用:搜索篇
  4. win10 中的eclipse无法新建web项目
  5. rocketmq 消息指定_闲话RocketMQ
  6. 排序算法系列:快速排序算法
  7. linux从新手到高手,1.3 养成良好的Linux操作习惯免费阅读_循序渐进Linux(第2版) 基础知识 服务器搭建 系统管理 性能调优 虚拟化与集群应用免费全文_百度阅读...
  8. redhat配置oracle yum源,Redhat5和6 YUM源配置的区别
  9. 正则表达式批量重命名
  10. WATM与Tivoli、SIM同获2007网络技术大会网管系统选择奖
  11. 云南等保2.0介绍,等保合规二级、三级整改所需设备清单和具体解决方案
  12. Activity启动过程(一)AMS
  13. 医院时钟系统(子母钟系统)构成及应用
  14. 继续学习-CSS3页面美化之静态美化
  15. 物理计算机主机ip在哪,查看电脑的物理地址_查看电脑的物理ip地址
  16. 利用微搭低代码操作微信缓存
  17. linux 原型软件,7款免费原型设计工具,总有一款是你的菜!
  18. SQL Server 简单模式下,误删除堆表记录如何恢复(绕过页眉校验)
  19. FleaPHP 开发指南 - 4. 命名规范和目录结构
  20. 红米k30 允许调用gpu调试层_2499元的红米K30S至尊纪念版,会是性价比最高的865神机吗?...

热门文章

  1. having vs where
  2. 基于Spring boot,使用idea方便地切换启动环境
  3. 按逆向思维定义软件测试,软件测试基础相关概念
  4. 微信小程序父级之间的传值_微信小程序自定义组件封装及父子间组件传值的方法...
  5. fastreport 打印两个list_Smaller And Smarter Python数据结构:合并两个有序链表
  6. CGLIB依赖ASM(关于java字节码框架ASM的学习)
  7. java转换文本文件到xlsx(自制缓冲区,无需先验文件行数)
  8. MarkdownPad 汉化破解(含下载地址)
  9. 算法运行时间中的对数
  10. HDU2049(错列排序)