I have always envied Ruby developers for the great test frameworks they have at their disposal, such as RSpec or Cucumber. However, I am mostly working in pure Java projects, which means having to use JUnit for writing tests. Of course, I could have used RSpec with JRuby to test my applications, but that would mean giving up type-safety when writing tests. Reimplementing something like RSpec in Java doesn't really make sense, as Java doesn't provide the required syntactic flexibility. It seemed like I was stuck with JUnit.
This changed last year, when Xtext introduced the possibility to reuse and integrate all kinds of Java language constructs right into your own DSL. This makes it possible to create DSLs that seamlessly interact with Java objects while providing excellent tool support. A good demonstration of the potential Xtext is Xtend. Xtend is a language extending Java with additional constructs such as lambda expressions that compiles to idiomatic Java code.
Using Xtext, it has now become feasible to create a language specifically for testing Java programs that tightly integrates with Java and features a syntax specifically designed for writing concise and readable tests. This is exactly what I have been working on together with my colleague Birgit. We are now happy to announce the first official Jnario release. To get started head over to the Jnario website.
What is it?
If you don't know Jnario yet, Jnario is a new test framework for Java enabling you to write concise tests that clearly express the expected behavior of your code (this is why we refer to tests written in Jnario as specs). This is possible, because Jnario is a language being specificially built for the purpose of writing tests. Specs written in Jnario compile into Java source code and you can seamlessly interact with Java objects. Jnario provides two languages for specifying the behavior of your Java programs. The first one is good for writing specs from a developer perspective:
The second one can be used to create executable acceptance specifications from a customer perspective similar to Cucumber:
Jnario provides custom assertion and matchers, for example, you can use
should statement to express the expected behavior of objects. There is also a short cut available:
=> which has the same effect.
// equality true should be true 1 + 1 should not be 1 "something" should not be null 1 + 1 => 2 // expecting exceptions new Stack().pop throws EmptyStackException // types "a string" => typeof(String) // strings "something" should contain "thing" "something" should not contain "any" // iterables list("something") should contain "something" list("something") should not contain "something else" // using xtend's "with" operator "hello world" => [ length => 11 it should startWith("hello") it should endWith("world") ]
=> try to give you as much context information as possible.
The error message will print the values of all expressions and their sub-expressions. For example:
Expected x.toUpperCase should not be "HELLO" but x.toUpperCase is "HELLO" x is "hello"
Another great thing about Jnario is that you can easily generate documentation from your specs (the complete Jnario documentation has been generated from specs written in Jnario). This is what the HTML documentation looks like that is generated form the previous stack specification:
and for the calculator example:
Jnario provides a fully integrated IDE for Eclipse, which means its tooling provides all the amenities one would expect from a state of the art IDE: syntax highlighting, code completion, validation, and incremental build. However, this doesn't mean that Jnario is restricted to Eclipse. Compiler, documentation generator and runtime are completely independent from Eclipse and can also be used, for example, via Maven.
In this first release of Jnario we focused on the basic features of each language, but we have lots of ideas about how to further improve Jnario. The three main features that we plan focusing on in the next releases are:
- Provide a simplified syntax for the creation of mock objects, leveraging the support for lambda expressions in Xtend.
- Make it easier to reuse step implementations from other steps when implementing scenarios.
- Integrate spec execution result (passing, failing, pending) into the generated documentation.