How to test file upload in Grails

I have a controller that takes in a file as part of the parameter. I'm wondering how can I test this?

my controller action:

def save () {
  def colorInstance = new Color(params.color)
  CommonsMultipartFile file = request.getFile('color.filename')
  fileUploadService.upload(colorInstance, file, "foldername")
  if (requestInstance.save(flush: true)) {
    withFormat {
      html {redirect(action: "list") }
      js {render "test"}
    }
  }
}

I've started with something like this:...

import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor

@TestFor(ColorController)
@Mock(Color)
class ColorControllerTests {

    @Before
    void setUp() {
        controller.fileUploadService = new FileUploadService
    }
}

Question

  • I can't figure out how to test the CommonsMultipartFile for file upload.
  • Also, this test case will sit in unit test folder. How can I execute it?

Answers


Since the request will be multipart during file upload, the actual request servlet would be MultipartHttpServletRequest. For unit test case, mock the same and use it as the request in controller. On successful mocking you should be able to addFile in tests and getFile in action.

import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor

@TestFor(ColorController)
@Mock(Color)
class ColorControllerTests {

    @Before
    void setUp() {
        controller.fileUploadService = new FileUploadService
        //Mock MultipartHttpServletRequest somethign like below
        controller.metaClass.request = mockFor(MultipartHttpServletRequest).createMock()
    }

    void testFileUpload(){
         //Add a mock multipart file to request
         controller.request.addFile(new MockMultipartFile('myFile', 'IronMan3.jpg', 'image/jpeg', "1234567" as byte[]))

         //call the controller action
         //assert response
    }
}

I am using Grails 2.4, and you can simply use GrailsMockMultipartFile and request.addFile method in your unit test.

This code works on Grails 2.4.4, with Spock testing framework:

Controller side:

class FileUploadController {

    def upload() {
        def multipartFile = request.getFile('requestParamName')
        if (multipartFile.empty) {
            flash.message = 'Error: file cannot be empty'
            render(view: 'upload')
            return
        }

        // do something now with your file
    }
}

Unit test side:

import grails.test.mixin.TestFor
import org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile
import spock.lang.Specification

@TestFor(FileUploadController)
class FileUploadControllerSpec extends Specification {

    void "upload should add flash error message if empty file in request"() {
        given:
        def multipartFile = new GrailsMockMultipartFile('requestParamName', 'someExcelFile.xls', 'application/vnd.ms-excel', new byte[0])
        request.addFile(multipartFile)

        when:
        controller.upload()

        then:
        assertEquals('Error: file cannot be empty', flash.message)
    }

}

The accepted answer did not work for me. The following code did:

import org.junit.Before
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import org.springframework.mock.web.MockMultipartHttpServletRequest
import org.springframework.mock.web.MockMultipartFile

@TestFor(ColorController)
class ColorControllerTests {

    def mockRequest

    @Before
    void setUp() {
        mockRequest = new MockMultipartHttpServletRequest()
        controller.metaClass.request = mockRequest

        // your service here
        controller.fileUploadService = new FileUploadService
    }

    void testFileUpload(){
         //Add a mock multipart file to request
         mockRequest.addFile(new MockMultipartFile('myFile', 'IronMan3.jpg', 'image/jpeg', "1234567" as byte[]))

         //call the controller action
         //assert response
    }
}

Need Your Help

Devise Account Unlock Returning "Unlock Token is Invalid"

ruby-on-rails devise

I have a standard devise implementation. Everything is working except for account unlocking (locking works fine).

Stemming algorithm that produces real words

php nlp stemming snowball porter-stemmer

I need to take a paragraph of text and extract from it a list of "tags". Most of this is quite straight forward. However I need some help now stemming the resulting word list to avoid duplicates.