Spring MVC Junit testing MultipartFile always empty

5.2k views Asked by At

I'm using spring-mvc version 4.1.6-RELEASE with Junit 4.12 and java 1.7, I have a controller for file uploading who works when I've tested it on server with Browser. But when I try to test it with junit the mockfilemultipart is always empty and I'm sure isn't so in the test class.

This is my servlet-context.xml

<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!--  beans:import resource="../controller-context.xml"/-->

<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>

<beans:bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>

<context:component-scan base-package="it.isfol.iweb" />

This is the controller

package it.isfol.iweb.controller.pianoattivita;

import it.isfol.iweb.bean.wrappers.PianoAttivitaWrapper;
import it.isfol.iweb.controller.common.IsfolController;
import it.isfol.iweb.exceptions.IWebFatalException;
import it.isfol.iweb.service.pianoattivita.FilePianoAttivitaService;
import it.isfol.iweb.util.SessionConstant;

import java.util.Arrays;
import java.util.Collection;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class UploadPianoAttivitaController extends IsfolController {

    /**
     * 
     */
    private static final long        serialVersionUID = 5455170192118107020L;
    private static final String      UPLOAD_PAGE      = "upload/upload";
    private final Logger             logger           = LoggerFactory.getLogger(UploadPianoAttivitaController.class);
    @Autowired
    private FilePianoAttivitaService filePianoAttivitaService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String uploadHomePage(HttpSession session) {
        logger.info("I'm home");
        return goToUploadPage(session);
    }

    @RequestMapping(value = "/uploadInit", method = RequestMethod.GET)
    public String uploadPageRedirect(HttpSession session) {
        logger.info("redirect into upload");
        return goToUploadPage(session);
    }

    @RequestMapping(value = "/uploadPiano", method = RequestMethod.POST, produces = MediaType.TEXT_PLAIN_VALUE)
    @ResponseBody
    public String upload(@RequestParam("files[]") MultipartFile[] files, HttpSession session) throws IWebFatalException {
        logger.debug("Writing file to disk...");
        try {
            Collection<PianoAttivitaWrapper> piani = filePianoAttivitaService.getPianoAttivitaWrapperFromFiles(Arrays.asList(files), session.getId());
            session.setAttribute(SessionConstant.PIANO_ATTIVITA_LIST_WRAPPER, piani);
        } catch (IWebFatalException e) {
            throw e;
        } catch (Throwable t) {
            logger.error(t.getLocalizedMessage(), t);
            throw new IWebFatalException(t);
        }
        return "pianoAttivita";
    }

    private String goToUploadPage(HttpSession session) {
        logger.debug("redirect on upload page");
        sessionHelper.clearSessionPianoReference(session);
        return UPLOAD_PAGE;
    }

    public void setFilePianoAttivitaService(FilePianoAttivitaService filePianoAttivitaService) {
        this.filePianoAttivitaService = filePianoAttivitaService;
    }
}

Then my abstract class for testing

package it.isfol.iweb;

import java.io.IOException;
import java.util.Properties;

import org.junit.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@WebAppConfiguration(value = "src/main/webapp")
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml", "file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml" })
public abstract class IsfolIwebTester extends AbstractJUnit4SpringContextTests {

    private final Logger          logger         = LoggerFactory.getLogger(IsfolIwebTester.class);
    private Properties            testProperties = new Properties();
    @Autowired
    private WebApplicationContext webapp;
    protected MockMvc             mockMvc;

    @Before
    public void setup() {
        logger.debug("reading properties");
        try {
            testProperties.load(this.getClass().getResourceAsStream("/test-conf.properties"));
            this.mockMvc = MockMvcBuilders.webAppContextSetup(webapp).build();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } catch (Throwable e) {
            logger.error(e.getLocalizedMessage(), e);
        }
    }

    public String getProperty(String key) {
        return testProperties.getProperty(key);
    }
}

and finally the test class who extends the class above

package it.isfol.iweb.pianoattivita;

import it.isfol.iweb.IsfolIwebTester;

import org.apache.commons.io.FilenameUtils;
import org.apache.tika.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

public class FilePianoAttivitaTester extends IsfolIwebTester {

    private final Logger logger = LoggerFactory.getLogger(FilePianoAttivitaTester.class);

    @Test
    public void testRunning() {
        logger.debug("Test started");
        try {
            String originalFile = getProperty("test.file.pianoattivita.path");
            String originalName = FilenameUtils.getName(originalFile);
            byte[] content = IOUtils.toByteArray(getClass().getResourceAsStream(originalFile));
            MockMultipartFile file = new MockMultipartFile("testJunit", originalName, null, content);
            this.mockMvc.perform(MockMvcRequestBuilders.fileUpload("/uploadPiano").file(file)).andExpect(MockMvcResultMatchers.status().isOk()).andReturn().equals("pianoAttivita");
            this.mockMvc.perform(MockMvcRequestBuilders.get("/pianoAttivita")).andExpect(MockMvcResultMatchers.view().name("upload/upload"));
        } catch(Throwable t) {
            logger.error(t.getLocalizedMessage(), t);
            Assert.fail();
        }
    }
}

In the method upload of UploadPianoAttivitaController when I run Junit the param files[] contain 1 empty MultiPartFile, while when I run it on server and I upload a file from page everything is ok.

2

There are 2 answers

0
ivan2yk On

Try this way:

MockMultipartFile mockMultipartFile = new MockMultipartFile("file",
            "OriginalName.txt",
            "text/plain",
            rateExceptionsFile);

    mockMvc.perform(multipart(BASE_PATH + "/uploadFile")
            .file(mockMultipartFile)
            .contentType(MediaType.MULTIPART_FORM_DATA))
            .andExpect(status().isOk());
0
Salvador Almaraz On

The name of your RequestParam for files must match with the MockMultipartFile name.

In your case is "files []" and in the mock is "testJunit", you can watch your HttpServletRequest params in your controller.