The JVM Fanboy Blog 

Entries tagged [qunit]

Use QUnit to unit-test stand-alone Nashorn scripts

by vincent


Posted on Sunday Nov 01, 2015 at 05:09PM in Nashorn


I've been writing a lot of standalone Oracle Nashorn scripts lately. I'm just so productive when writing server-side JavaScript code, especially when I have the versatility of the Java run-time class library at my fingertips at the same time as well!

As I said in my previous post, currently IDE and tools integration leaves something to be desired for developers creating standalone Nashorn scripts . I had a small Twitter conversation that seemed to confirm this. NetBeans IDE can run Nashorn scripts when not using projects, but there is no dedicated project type for standalone Nashorn project yet.

As things stand, I currently write my Nashorn scripts still in a text editor and do not use the Java tools that I usually would have (auto-complete, integrated debugger, unit test integration, running project inside IDE...). I've learned since that other people write Java code to start and debug stand-alone Nashorn scripts (NetBeans IDE has this awesome feature where it can seamlessly debug JavaScript code when invoked from Java code) and write wrappers around their JS unit-tests so that Java code invokes it. I would do this too on bigger projects, but as my current Nashorn projects are relatively small, I chose not to follow that route just yet.

Using QUnit with Nashorn

I am a supporter of TDD (test-driven development), so I was looking for an easy-to-use JavaScript-based unit testing library that is compatible with Nashorn.

After some Googling, I found some blog posts talking about Nashorn and unit-testing. Most of them talked about what I just mentioned: wrapping Nashorn scripts in Java code. I found one interesting StackOverflow post where Christian Michon asked exactly what I was looking for. In this post, Sirko responded by suggesting using QUnit (by the JQuery Foundation team), since it can use callbacks and therefore work in any JavaScript environment.

I could not get the posted code to work with the latest release versions of Nashorn and QUnit. After some modifications I got it working and decided to post it here, perhaps it is useful for someone else.

I will evaluate other JavaScript unit-tests frameworks later, especially Jasmine caught my eye, but for now QUnit seems to work fine with my test scripts.

QUnit callbacks

QUnit has an API where callbacks can be registered for reporting single test and/or complete test suites results. Using these callbacks, it's very easy to let QUnit make use of Nashorn's print() function to print to the console. For my projects, that is currently sufficient, as I do not use CI (Continuous Integration) servers for my Nashorn projects at this time and manually run the tests from the command-line (I'd not recommend this work-flow for bigger projects, of course)

Example

Here's how I got QUnit working with Nashorn:

I could only get it to work when using the JVM-NPM project. It implements the well-known require() function from Node.js on JVM JavaScript engines (Nashorn, Rhino and the sadly seemingly inactive open-source DynJS effort)

  • In your project directory, create a "tests" directory and a tests/include directory.
  • Download the latest version of QUnit at qunitjs.com (qunit-1.20.0.js at the time of this writing). Only the .js file is needed, the .css will not be used. Place the JavaScript file in the tests/include/ directory.
  • From a command-ine window, navigate to a temporary downloads directory and type "git clone https://github.com/nodyn/jvm-npm" (requires Git, but I'm betting pretty much all developers have installed this on their system these days).
  • Copy the jvm-npm/src/main/javascript/jvm-npm.js file to your tests/include directory
  • Create a Nashorn javascript library that loads and sets up QUnit to work with Nashorn. This code has been largely based on the mentioned StackOverflow post.
load("include/jvm-npm.js");
var QUnitModule = require("include/qunit-1.20.0.js");

QUnit = QUnitModule.QUnit


QUnit.log(function(details) {
    if (!details.result) {
      var message = details.name + "\tFAIL" + details.source;
      message += " actual: " + details.actual + " <> expected: " + details.expected;
      print(message);
    }		
})


QUnit.done(function(details) {
    print("time:\t",details.runtime,"ms");
    print("total:\t",details.total);
    print("passed:\t",details.passed);
    print("failed:\t",details.failed);
})
    

Store this file in your tests/includes directory and call it "qunit-nashorn.js". It's a bit hackish, but it loads and sets up the QUnit callbacks and makes available the QUnit as a global object.

Now creating test scripts is the relatively easy part. Some dummy code that you could place in the test directory and call "dummytest.js":

load("include/qunit_nashorn.js");

var testMethod = function(b) {
    return b;
}

QUnit.test("testOK1", function(a) {
    var res = testMethod(true);
    a.equal(res, true);
})


QUnit.test("testOK2", function(a) {
    var res = testMethod(false);
    a.equal(res, false);
})


QUnit.test("testFails1", function(a) {
    var res = testMethod(false);
    a.equal(res, true);
})


QUnit.test("testFails2", function(a) {
    var res = testMethod(true);
    a.equal(res, false);
})


QUnit.load();
    

When running jjs dummytest.js from your tests directory, should result in output like:

Nashorn console output example