Unit testing using MockMultipartHttpServletRequest (throws NullPointerException in ItemInputStream.makeAvailable)

时间秒杀一切 提交于 2019-12-07 01:15:09

问题


I've written a transformer class that takes an HttpServletRequest and transforms it into another type that holds a pointer to the InputStream from the servlet request. (The idea is to abstract the incoming transport protocol from the request handling, so I could also write a similar transformer from FTP, for instance.)

Now I'm trying to write a unit test for this, and I'm having problems. I've managed to figure out the correct boilerplate to create a valid Multipart HTTP request (using the Spring classes MockMultipartHttpServletRequest and MockMultipartFile), but now I get a NullPointerException in the initialize() method of my UploadRequest class. I'm guessing the problem is that somehow the stream inside the MockMultipartHttpServletRequest isn't being initialized correctly, but I can't figure out what I should do differently.

Any suggestions would be gratefully accepted!

This is the stack trace:

java.lang.NullPointerException
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:976)
    at org.apache.commons.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:886)
    at java.io.InputStream.read(InputStream.java:82)
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:96)
    at org.apache.commons.fileupload.util.Streams.copy(Streams.java:66)
    at org.apache.commons.fileupload.MultipartStream.readBodyData(MultipartStream.java:592)
    at org.apache.commons.fileupload.MultipartStream.discardBodyData(MultipartStream.java:618)
    at org.apache.commons.fileupload.MultipartStream.skipPreamble(MultipartStream.java:637)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.findNextItem(FileUploadBase.java:984)
    at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:965)
    at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
    at org.apache.commons.fileupload.servlet.ServletFileUpload.getItemIterator(ServletFileUpload.java:148)
    at com.ooyala.UploadRequest.initialize(UploadRequest.java:51)
    at com.ooyala.UploadRequestTest.testCreateFromServletRequest(UploadRequestTest.java:57)

Here's an abbreviated version of my transformer class:

public class UploadRequest {
  private Map<String, String> params;
  private InputStream strIn;
  private Logger Log = Logger.getLogger(UploadRequest.class.getName());

  public UploadRequest()
  {
    params = new HashMap<String, String>();
  }

  public void initialize(HttpServletRequest sRequest, 
                         ServletFileUpload upload)
    throws IOException, FileUploadException
  {
    Enumeration<String> paramNames = sRequest.getParameterNames();
    while (paramNames.hasMoreElements()) {
      String pName = paramNames.nextElement();
      params.put(pName, sRequest.getParameter(pName));
    }
    params.put("request_uri", sRequest.getRequestURI());

    FileItemIterator iter = upload.getItemIterator(sRequest);
    while (iter.hasNext()) {
      FileItemStream item = iter.next();
      try {
        if (!item.isFormField()) {
          // Skip form fields
          params.put("original_file_name", item.getName());
          strIn = item.openStream();
        } 
      } catch (IOException ex) {
        Log.severe("File uploading exception: " + ex.getMessage());
        throw ex;
      }
    }
  }

And here's the unit test:

import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
// etc.... other imports

@RunWith(JMock.class)
public class UploadRequestTest {
  private UploadRequest upRequest;

  @Before
    public void setUp()
    {
      context.setImposteriser(ClassImposteriser.INSTANCE);
      upRequest = new UploadRequest();
    }

  @Test
    public void testCreateFromServletRequest()
      throws IOException, FileUploadException
    {
      String text_contents = "hello world";

      MockMultipartHttpServletRequest sRequest = 
        new MockMultipartHttpServletRequest();
      sRequest.setMethod("POST");
      String boundary = generateBoundary();
      String contentType = "multipart/form-data; boundary="+boundary;
      sRequest.setContentType(contentType);
      sRequest.setRequestURI("/foo");
      sRequest.addParameter("test_param","test_value");
      sRequest.addFile(
        new MockMultipartFile("file1","test_upload.txt","text/plain",
          text_contents.getBytes()));

      ServletFileUpload upload = new ServletFileUpload();
      assertTrue(upload.isMultipartContent(sRequest));

      upRequest.initialize(sRequest, upload);
    }
}

回答1:


I have the same issue and I googled but no answer. I plugged in the source code from the library, You need to send content, whatever. The library might need to check if it is null in the skip method

MockMultipartHttpServletRequest request
request.setContent("whatever".getBytes());

Posted here for others




回答2:


  1. Add boundary condition
  2. Generate contents as follows

    MockMultipartHttpServletRequest request = 
        this.generateMockMultiPartHttpServletRequest(true);
    MockMultipartFile mockMultipartFile = null;
    try {
        request.setContentType("multipart/form-data; boundary=-----1234");
        request.setCharacterEncoding("text/plain");
        String endline = "\r\n";
        String bondary = "-----1234";
        String textFile = this.encodeTextFile("-----1234", "\r\n", "file","test.csv",
            "text/UTF-8", FileUtils.readFileToString((new File(csvFilePath)), "UTF-8"));
        StringBuilder content = new StringBuilder(textFile.toString());
        content.append(endline);
        content.append(endline);
        content.append(endline);
        content.append("--");
        content.append(bondary);
        content.append("--");
        content.append(endline);
        request.setContent(content.toString().getBytes());
        request.setMethod("POST");
        mockMultipartFile = new MockMultipartFile("file",
        FileUtils.readFileToByteArray(new File(csvFilePath)));
    } catch (Exception e1) {
        e1.printStackTrace();
    }
     request.addFile(mockMultipartFile);
    

Function to encode text

    private String encodeTextFile(String bondary, String endline, String name, 
        String filename, String contentType, String content) {

        final StringBuilder sb = new StringBuilder(64);
        sb.append(endline);
        sb.append("--");
        sb.append(bondary);
        sb.append(endline);
        sb.append("Content-Disposition: form-data; name=\"");
        sb.append(name);
        sb.append("\"; filename=\"");
        sb.append(filename);
        sb.append("\"");
        sb.append(endline);
        sb.append("Content-Type: ");
        sb.append(contentType);
        sb.append(endline);
        sb.append(endline);
        sb.append(content);
        return sb.toString();
    }



回答3:


I went through the same problem, after searching lot I got this post in which I answered with code that solved my problem.

The Shriprasad's solution works well for text file. But I had some problems with binary files.

https://stackoverflow.com/a/30541653/2762092



来源:https://stackoverflow.com/questions/9474813/unit-testing-using-mockmultiparthttpservletrequest-throws-nullpointerexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!