Writing unit tests for our handlers in Ratpack is easy with RequestFixture
. We invoke the handle
method and use a Handler
or Chain
we want to test as argument. We can provide extra details on the fixture instance with a second argument, for example adding objects to the registry or setting the request method. The handle
method returns a HandlingResult
object. This object has the method exception
that we can use to see if an exception occurred in our code under test. The method throws a HandlerExceptionNotThrownException
if the expected exception doesn't occurr.
In the following example we have two feature methods to check if an exception occurred or not:
package sample import ratpack.handling.Context import ratpack.handling.Handler import ratpack.test.handling.RequestFixture import spock.lang.Specification class HandlerSpec extends Specification { def 'check exception is thrown'() { given: def result = RequestFixture.handle new SampleHandler(true), Action.noop() expect: result.exception(Exception).message == 'Sample exception' } def 'check no exception is thrown'() { given: def result = RequestFixture.handle new SampleHandler(false), Action.noop() when: result.exception(Exception) then: thrown(HandlerExceptionNotThrownException) } } class SampleHandler implements Handler { /** * Indicate if we need to create an * error with an exception or not. */ private final boolean throwException = false SampleHandler(final boolean throwException) { this.throwException = throwException } @Override void handle(final Context ctx) throws Exception { if (throwException) { // Throw a sample exception. ctx.error(new Exception('Sample exception')) ctx.response.send() } else { // No exceptions. ctx.response.send('OK') } } }
Instead of using the exception
method of HandlingResult
we can add a custom ServerErrorHandler
to the fixture registry. Exceptions are handled by the error handler and we can check if an exception occurred or not via the error handler. In the following code we use a custom error handler:
package sample import ratpack.error.ServerErrorHandler import ratpack.handling.Context import ratpack.handling.Handler import ratpack.test.handling.RequestFixture import spock.lang.Specification class HandlerSpec extends Specification { /** * Error handler to capture exceptions. */ private specErrorHandler = new SpecErrorHandler() /** * Add error handler as {@link ServerErrorHandler} * implementation to the fixture registry. */ private fixtureErrorHandler = { fixture -> fixture.registry.add ServerErrorHandler, specErrorHandler } def 'check exception is thrown'() { when: RequestFixture.handle new SampleHandler(true), fixtureErrorHandler then: specErrorHandler.exceptionThrown() and: specErrorHandler.throwable.message == 'Sample exception' } def 'check no exception is thrown'() { when: RequestFixture.handle new SampleHandler(false), fixtureErrorHandler then: specErrorHandler.noExceptionThrown() } } class SampleHandler implements Handler { /** * Indicate if we need to create an * error with an exception or not. */ private final boolean throwException = false SampleHandler(final boolean throwException) { this.throwException = throwException } @Override void handle(final Context ctx) throws Exception { if (throwException) { // Throw a sample exception. ctx.error(new Exception('Sample exception')) ctx.response.send() } else { // No exceptions. ctx.response.send('OK') } } } /** * Simple implementation for {@link ServerErrorHandler} * where we simply store the original exception and * add utility methods to determine if an exception is * thrown or not. */ class SpecErrorHandler implements ServerErrorHandler { /** * Store original exception. */ private Throwable throwable /** * Store exception in {@link #throwable} and * set response status to {@code 500}. * * @param context Context for request. * @param throwable Exception thrown in code. * @throws Exception Something goes wrong. */ @Override void error(final Context context, final Throwable throwable) throws Exception { this.throwable = throwable context.response.status(500) } /** * @return {@code true} if error handler is invoked, {@code false} otherwise. */ boolean exceptionThrown() { throwable != null } /** * @return {@code true} if error handler is not invoked, {@code false} otherwise. */ boolean noExceptionThrown() { !exceptionThrown() } }
Written with Ratpack 1.4.5.