Search code examples
unit-testinggrailsgrails-controller

Using custom renderer in grails unit testing (and in general) on JSON content types


I am trying to get a custom JSON renderer for exceptions working in my REST api.

I was able to get a custom marshaller working that did most of what I needed, but I would like to have control over the context that I don't have access to in the marshaller. The grails documentation shows how to write a custom renderer, and I have one that I think should work, but I can't use it during unit testing my REST controller.

Grails docs: http://grails.org/doc/2.3.4/guide/webServices.html#customRenderers

Does anyone know how I would initialize this renderer to be used in my controller actions during unit testing?

The above documentation only says how to set it up in the resources.groovy file.

When I was using the marshaller, I was able to do:

def setup(){
    //Set up the custom JSON marshallers
    JSON.registerObjectMarshaller(new CusomMarshaller(), 1)
}

But I don't see an equivalent method for Renderers. Can anyone point me in the right direction?


Further details:

Here is my renderer:

class JSONExceptionRenderer extends AbstractRenderer<Exception>{

JSONExceptionRenderer(){
    super(Exception, [MimeType.JSON, MimeType.HAL_JSON, MimeType.TEXT_JSON] as MimeType[])
}

@Override
void render(Exception object, RenderContext context) {
    log.warn("RENDERING")
    Exception exception = (Exception) object

    //Default to internal error
    Integer code = 500

    //If it is a defined exception with a more appropriate error code, then set it
    if(exception instanceof RestException){
        code = (Integer) ((RestException) exception).getCode()
    }else if(exception instanceof MissingResourceException){
        code = 404
    }
    context.status = HttpStatus.valueOf(code)

    //Write the JSON
    Writer writer = context.getWriter()
    Map content = ["code":code, "status":"error", "message":exception.message]
    JsonBuilder builder = new JsonBuilder(content)
    builder.writeTo(writer)

}
}

And this is the way I am trying to get it to work:

try{
  log.info "Throwing exception"
  throw new NullPointerException("Test Exception")
}catch(Exception ex){
  render ex as JSON
}

Thanks!


Solution

  • If you are using spock, you can inject the bean directly in Specification.

    @TestFor(MyController)
    class MyControllerSpec extends spock.lang.Specification {
         def myCustomRenderer //bean name used in resources.groovy
    
         //continue with tests
    }
    

    If you are using junit tests, then you can use defineBeans as:

    @TestFor(MyController)
    class MyControllerTests {
        void setup() {
             defineBeans {
                myCustomRenderer(com.example.MyCustomRenderer)
             }
        }
    
        //continue with tests
    }
    

    You can refer this answer as well for use of defineBeans.

    I believe this is what you just need to do to test the behavior of the renderer.