View on GitHub


Spec-style testing for Java

Download this project as a .zip file Download this project as a tar.gz file


Behavior-Driven Development testing for Java using lambdas. Inspired by RSpec and Machine.Specifications.

Build status


Why create another testing framework for Java, and why use lambdas?

JavaSpec attempts to be:

There are many testing libraries out there with some of these characteristics, but expresiveness does not need to come at the cost of adding complexity. For example you can write your tests in Ruby or Groovy (as the author once considered), but now you're adding more components between your test and production code, adding new dependencies, and losing out on searchability.

Lambdas are the weapon of choice for turning simple expressions into one-liners. A test with one assertion can be 1 line instead of several for tagging and creating whole, new test method.


JavaSpec is located in the Maven Central Repository, under the following coordinates:


It depends upon JUnit and Java 8+.

Getting started

There's no magic in how JavaSpec works. This guide describes JavaSpec in terms of its similarities to popular libraries instead of pretending like these are radical, never-before-seen ideas.

It runs on JUnit

In JUnit, you create a test class and put @Test methods in it. JavaSpec is similar:

A simple "Hello World" test looks like this:

class GreeterTest {
  It says_hello = () -> assertEquals("Hello World!", new Greeter().sayHello());

As with JUnit, you get 1 instance of your test class per test. Each It is its own test.

Finally, note that the It field is named says_hello instead of the conventional saysHello. This is done so that JavaSpec can convert that verb phrase into a human readable form by replacing underscores with spaces. When you run this test, JUnit will report results for says hello.

It's like Machine.Specifications

Machine.Specifications and JavaSpec represent the different steps of a test the same way:

You can think of Establish and Because as what a @Before method would do in JUnit. These lambdas run before each It lambda in the same class (and also before It fields in inner classes). Cleanup is like @After in JUnit, running after each It in the same test class.

Unlike MSpec, your lambdas execute in an instance of the class in which they are declared. Non-static helper methods in your test class are fair game to be called from any step.

A JavaSpec test fixture looks like this:

class GreeterWithFixtureTest {
  private final PrintStreamSpy printStreamSpy = new PrintStreamSpy();
  private Widget subject;
  private String returned;

  Establish that = () -> subject = new Widget(printStreamSpy);
  Because of = () -> returned =;
  Cleanup close_streams = () -> {
    if(subject != null)

  It returns_bar = () -> assertEquals("bar", returned);
  It prints_baz = () -> assertEquals("baz", printStreamSpy.getWhatWasPrinted());

It's like RSpec

RSpec lets you organize hierarchies of tests and fixtures with describe and context, and each level in the tree can have its own before and after methods to work the test fixture. JavaSpec provides nested contexts by nesting context classes (inner, non-static classes) in the top-level test class.

Each class can have as many It lambdas as you want, plus up to 1 of each type of fixture lambda (Establish, Because, and Cleanup) to build up the test fixture. As with RSpec, setup runs outside-in and cleanup runs inside-out. If you happen to have an Because in an outer class and an Establish in an inner class and wonder which one runs first, the outer class lambdas run first (i.e. Because runs first).

An example of using nested contexts:

class WidgetTest {
  private Widget subject;
  Establish that = () -> subject = new Widget();

  class foo {
    private String returned;
    Because of = () -> returned = subject.sayHello();
    It says_hello = () -> assertEquals("Hello World!", returned);

  class bar {
    class given_a_multiple_of_3 {
      It prints_fizz = () -> assertEquals("fizz",;

    class given_a_multiple_of_5 {
      It prints_buzz = () -> assertEquals("buzz",;

In short:

If you have any other questions

Hopefully JavaSpec works like you think it does.

For times when it doesn't, start by looking at the tests on JavaSpecRunner and related classes.

If that still doesn't do the trick, feel post an issue or submit a pull request with any suggested modifications.

Future work

Release history