Cucumber JVM: Test if the correct exception is thrown

samach picture samach · Jun 24, 2013 · Viewed 22.1k times · Source

How to test that the correct exception is thrown when using Cucumber JVM? When using JUnit, I would do something like this:

@Test(expected = NullPointerException.class)
public void testExceptionThrown(){
    taskCreater.createTask(null);
}

As you can see, this is very elegant. But how can I achieve the same elegance, when using cucumber JVM? My test looks like this right now:

@Then("the user gets a Null pointer exception$")
public void null_exception_thrown() {
    boolean result = false;
    try {
        taskCreater.createTask(null);
    } catch (NullPointerException e) {
        result = true;
    }
    assertTrue(result);
}

Note the need for a try..catch followed by an assertTrue on a flag.

Answer

Niel de Wet picture Niel de Wet · Apr 3, 2014

Testing the not-happy-path can be hard. Here's a nice way that I've found to do it with cucumber.

Scenario: Doing something illegal should land you in jail
    Then a failure is expected
    When you attempt something illegal
    And it fails.

OK, don't shoot me because I put the Then before the When, I just think it reads better but you don't have to do that.

I store my excepions in a (cucumber-scoped) world object, but you could also do it in your step file, but this will limit you later.

public class MyWorld {
    private boolean expectException;
    private List<RuntimeException> exceptions = new ArrayList<>();

    public void expectException() {
        expectException = true;
    }

    public void add(RuntimeException e) {
        if (!expectException) {
            throw e;
        }
        exceptions.add(e);
    }

    public List<RuntimeException> getExceptions() {
        return exceptions;
    }
}

Your steps are then pretty simple:

@Then("a failure is expected")
public void a_failure_is_expected() {
    myWorld.expectException();
}

In a step where you are (at least sometimes) expecting an exception, catch it and add it to the world.

@When("you attempt something illegal")
public void you_attempt_something_illegal() {
    try {
        myService.doSomethingBad();
    } catch (RuntimeException e) {
        world.add(e);
    }
}

Now you can check whether the exception was recorded in the world.

@And("it fails")
public void it_fails() {
    assertThat(world.getExceptions(), is(not(empty()));
}

The most valuable thing about this approach is that it won't swallow an exception when you don't expect it.