How to write unit tests with commons-fileupload?
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 writ开发者_如何学运维e tests for commons-fileupload.
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();
}
}
}
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
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...
精彩评论