Question

I'm working in a framework that uses commons-fileupload.

Now I need to write unit test classes. My doubt is how to write mock tests if ServletFileUpload is not an interface? There are another way to test my classes?

Yesterday I wrote unit tests using mockito for Servlet Parts, and it's easy. But I can't think how to write tests for commons-fileupload.

Was it helpful?

Solution

You could go back to basics and hand roll your mock object by either wrapping or extending and overriding. Sometimes its easier to not depend on a mocking framework for everything.

Mocking Mocking and Testing Outcomes

OTHER TIPS

You could use Commons HTTPClient to build the multipart stream:

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletFileUploadMock {

    public static class FileUpload {

        private final String filename;
        private final String mimeType;
        private final byte[] contents;

        public FileUpload(String filename, String mimeType, byte[] contents) {
            this.filename = filename;
            this.mimeType = mimeType;
            this.contents = contents;
        }

    }

    public static HttpServletResponse mockServletFileUpload(HttpServlet servlet, List<FileUpload> files,
            Map<String, String> queryParams) throws IOException, ServletException {

        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        for (FileUpload f : files) {
            builder = builder.addBinaryBody(f.filename, f.contents, ContentType.create(f.mimeType), f.filename);
        }
        HttpEntity entity = builder.build();

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        entity.writeTo(os);
        ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());

        HttpServletRequest mockRequest = mock(HttpServletRequest.class);
        when(mockRequest.getMethod()).thenReturn("POST");
        when(mockRequest.getContentType()).thenReturn(entity.getContentType().getValue());
        when(mockRequest.getContentLength()).thenReturn((int)entity.getContentLength());
        when(mockRequest.getInputStream()).thenReturn(new MockServletInputStream(is));

        // Mock query params
        for (Entry<String, String> p : queryParams.entrySet()) {
            when(mockRequest.getParameter(p.getKey())).thenReturn(p.getValue());
        }

        HttpServletResponse mockResponse = mock(HttpServletResponse.class);

        servlet.service(mockRequest, mockResponse);

        return mockResponse;
    }

    public static class MockServletInputStream extends ServletInputStream {

        private final InputStream delegate;

        public MockServletInputStream(InputStream delegate) {
            this.delegate = delegate;
        }

        @Override
        public int read() throws IOException {
            return delegate.read();
        }

    }
}

I would consider wrapping your FileUpload calls in another layer. While it might sound like overkill, it would allow you to switch upload libraries very quickly with the added ability to better unit test your calls...It seems like you are tightly coupling your app to commons-fileupload...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top