Aug 12, 2008

Grails controller unit tests for uploading a file

I want 'test first' developing grails controller. Until now the scaffolding produces integration tests and these tests are executed in a grails environment with all the injected methods and properties from grails like: request, flash, params and so on.

But for unit tests i have to mock that, because i want no dependencies of other components.

Glen Smith has described in his blog how to achieve that:
http://blogs.bytecode.com.au/glen/2008/03/12/mockfor-march---unit-testing-grails-controllers.html
So i created a AbstractControllerTestCase:

abstract class AbstractControllerTest extends GroovyTestCase {

// ControllerTest's have to provide the controllerClass
// def controllerClass
def redirectParams
def renderParams
def params
def controller
def session
def flash
def message

void setUp(){
redirectParams= [:]
params = [:]
session = [:]
flash = [:]
renderParams = [:]
controllerClass.metaClass.redirect = { Map args -> redirectParams = args }
controllerClass.metaClass.getParams = { -> params }
controllerClass.metaClass.getSession = { -> session }
controllerClass.metaClass.getFlash = { -> flash }
controllerClass.metaClass.message = { Map args -> message }
controllerClass.metaClass.render = { Map args -> renderParams = args }
}

void tearDown(){
def remove = GroovySystem.metaClassRegistry.&removeMetaClass
remove controllerClass
}

}


To test a controller method that handle a file upload i need to mock also the request as multipart request. My solution was to use the 'propertyMissing(String name,Object arg)' method invocation hook. The controller use a request property, so i provide a mocked request.

Here is the test method (Uses Spring MockHttpServletRequest):


void testImportToCSWFileIsEmpty(){
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest()
request.addFile(new MockMultipartFile("xmlFile"))
MetadataController.metaClass.propertyMissing << { String name, Object args ->
request
}
params.cswUrl = "http://mockedCsw"
controller.importToCSW()
assertEquals("metadata.import.csw.fileempty",flash.message)
}


Are there easier ways ?

2 comments:

Mike Hugo said...

have a look at the "testing" plugin for grails. It's still a work in progress, but might be helpful to you. I don't know that it specifically solves the problem with the file upload portion, but it does have a utility class to help with testing controllers; http://www.nabble.com/-ANN--Experimental-testing-plugin-tp18530858p18530858.html

Leigh said...

Thanks for a superb solution. I can't believe that MockMultipartHttpServletRequest is not supported in the integration tests. RUBBISH!