PDA

View Full Version : Testing file upload - how to send enctype?



mraible
Sep 7th, 2004, 12:18 AM
In order for file upload to work, I have to add enctype="multipart/form-data" to my HTML form. How do I mimic this in a unit test?

The code below results in the following error:

Failed to convert property value of type [java.lang.String] to required type [[B] for property 'file'; nested exception is java.lang.IllegalArgumentException: /tmp/test.txt



MockHttpServletRequest request =
new MockHttpServletRequest("POST", "/fileUpload.html");
request.addParameter("file", "/tmp/test.txt");
ModelAndView mav =
fileUpload.handleRequest(request, new MockHttpServletResponse());

Alef Arendsen
Sep 13th, 2004, 03:15 PM
The MockHttp* classes don't support sending along the enctype. Some Http client libraries like Commons HttpClient do support it, but that's only a client, not a library implementing the HttpServlet* interfaces...

egervari
Sep 13th, 2004, 03:43 PM
I had this problem too and I didn't know how to solve it either. However, it's not that risky to leave it untested since the components that you are using are doing most of the work and the odds of it breaking are rather small. The best thing you can do is mock the byte[] array that comes back by facking a session-based form and adding the actual byte[] array to the command object in the session. This is how I test controllers on my apps using my framework, but it should be possible with spring too.

mraible
Sep 16th, 2004, 04:59 PM
The following is what I finally came up with. It uses some Mock items I found in Spring's source tree. I'd much rather send a file on the filesystem, but the MockFileItem works just as well.



public class FileUploadControllerTest extends TestCase {
private static Log log = LogFactory.getLog(FileUploadControllerTest.class);
private XmlWebApplicationContext ctx = null;
private FileUploadController fileUpload = null;

public void setUp() {
String[] paths = {"/WEB-INF/applicationContext*.xml",
"/WEB-INF/action-servlet.xml"};
ctx = new XmlWebApplicationContext();
ctx.setConfigLocations(paths);
ServletContext servletContext = new MockServletContext("file:web");

ctx.setServletContext(servletContext);
ctx.refresh();
fileUpload = (FileUploadController) ctx.getBean("fileUploadController");

// Create a mailSender that'll use Dumbster's ports
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("localhost");
mailSender.setPort(2525);
fileUpload.setMailSender(mailSender);
}

public void testUpload() throws Exception {
log.debug("testing upload...");
MockHttpServletRequest request =
new MockHttpServletRequest("POST", "/fileUpload.html");

MockCommonsMultipartResolver resolver = new MockCommonsMultipartResolver();
ctx.getServletContext();

request.setContentType("multipart/form-data");
request.addHeader("Content-type", "multipart/form-data");
assertTrue(resolver.isMultipart(request));
MultipartHttpServletRequest multipartRequest = resolver.resolveMultipart(request);

// setup a simple mail server using Dumbster
SimpleSmtpServer server = SimpleSmtpServer.start(2525);

ModelAndView mav =
fileUpload.handleRequest(multipartRequest, new MockHttpServletResponse());

server.stop();
// yes the getReceieved method is spelled wrong in Dumbster's API. ;-)
assertEquals(1, server.getReceievedEmailSize());

log.debug("model: " + mav.getModel());

assertNotNull(request.getSession().getAttribute("message"));

// ensure the file got uploaded
Resource uploadedFile = ctx.getResource("file:web/upload/test.xml");
assertTrue(uploadedFile.exists());

// delete the upload directory
Resource uploadDir = ctx.getResource("file:web/upload");
uploadedFile.getFile().delete();
uploadDir.getFile().delete();
assertFalse(uploadDir.exists());
}

public static class MockCommonsMultipartResolver extends CommonsMultipartResolver {

private boolean empty;

protected void setEmpty(boolean empty) {
this.empty = empty;
}

protected DiskFileUpload newFileUpload() {
return new DiskFileUpload() {
public List parseRequest(HttpServletRequest request) {
if (request instanceof MultipartHttpServletRequest) {
throw new IllegalStateException("Already a multipart request");
}
List fileItems = new ArrayList();
MockFileItem fileItem = new MockFileItem(
"file", "text/html", empty ? "" &#58; "test.xml", empty ? "" &#58; "<root/>"&#41;;
fileItems.add&#40;fileItem&#41;;
return fileItems;
&#125;
&#125;;
&#125;
&#125;

public static class MockFileItem implements FileItem &#123;

private String fieldName;
private String contentType;
private String name;
private String value;

private File writtenFile;
private boolean deleted;

public MockFileItem&#40;String fieldName, String contentType, String name, String value&#41; &#123;
this.fieldName = fieldName;
this.contentType = contentType;
this.name = name;
this.value = value;
&#125;

public InputStream getInputStream&#40;&#41; throws IOException &#123;
return new ByteArrayInputStream&#40;value.getBytes&#40;&#41;&#41;;
&#125;

public String getContentType&#40;&#41; &#123;
return contentType;
&#125;

public String getName&#40;&#41; &#123;
return name;
&#125;

public boolean isInMemory&#40;&#41; &#123;
return true;
&#125;

public long getSize&#40;&#41; &#123;
return value.length&#40;&#41;;
&#125;

public byte&#91;&#93; get&#40;&#41; &#123;
return value.getBytes&#40;&#41;;
&#125;

public String getString&#40;String encoding&#41; throws UnsupportedEncodingException &#123;
return new String&#40;get&#40;&#41;, encoding&#41;;
&#125;

public String getString&#40;&#41; &#123;
return value;
&#125;

public void write&#40;File file&#41; throws Exception &#123;
this.writtenFile = file;
&#125;

public File getWrittenFile&#40;&#41; &#123;
return writtenFile;
&#125;

public void delete&#40;&#41; &#123;
this.deleted = true;
&#125;

public boolean isDeleted&#40;&#41; &#123;
return deleted;
&#125;

public String getFieldName&#40;&#41; &#123;
return fieldName;
&#125;

public void setFieldName&#40;String s&#41; &#123;
this.fieldName = s;
&#125;

public boolean isFormField&#40;&#41; &#123;
return &#40;this.name == null&#41;;
&#125;

public void setFormField&#40;boolean b&#41; &#123;
throw new UnsupportedOperationException&#40;&#41;;
&#125;

public OutputStream getOutputStream&#40;&#41; throws IOException &#123;
throw new UnsupportedOperationException&#40;&#41;;
&#125;
&#125;
&#125;

RobertGloverJr
Feb 13th, 2007, 12:22 PM
The following is what I finally came up with.
... snip ...


// Create a mailSender that'll use Dumbster's ports

... snip ...


I went through a lot of pain using Dumbster until I discovered a Dumbster replacement written by someone who got frustrated with the bugs in Dumbster.
Below is the comment I placed in the program I wrote that originally used Dumbster:

* The first version of this program used the open source Dumbster mock mail server.
* However a robust, well-written open source alternative was later found and the program was re-written to use org.subethamail.wiser.Wiser instead of Dumbster.
* Wiser, according to their web site, is quote, "a smart replacement for Dumbster".
* For more information see: http://subethasmtp.tigris.org/wiser.html

I hope the word will get out about the benefits of Wiser. It's first class. By contrast, Dumbster is not being actively developed, and it has bugs that only surface when doing "strange" things like sending email to three recipients or using it within the IBM WSADS (or IBM RADS) IDE, where it throws socket exceptions concerning port 25 when the IDE reloads the Spring Application context because the developer changed the program source code. By contrast, Wiser works perfectly and uses the javax.mail api.