【问题标题】:Unit testing using MockMultipartHttpServletRequest (throws NullPointerException in ItemInputStream.makeAvailable)使用 MockMultipartHttpServletRequest 进行单元测试(在 ItemInputStream.makeAvailable 中抛出 NullPointerException)
【发布时间】:2012-03-17 12:05:54
【问题描述】:

我编写了一个转换器类,它接受一个 HttpServletRequest 并将其转换为另一种类型,该类型包含一个指向来自 servlet 请求的 InputStream 的指针。 (这个想法是从请求处理中抽象出传入的传输协议,所以我也可以从 FTP 编写一个类似的转换器。)

现在我正在尝试为此编写单元测试,但遇到了问题。我已经设法找出正确的样板来创建有效的多部分 HTTP 请求(使用 Spring 类 MockMultipartHttpServletRequest 和 MockMultipartFile),但现在我在 UploadRequest 类的 initialize() 方法中得到 NullPointerException。我猜问题是 MockMultipartHttpServletRequest 中的流不知何故没有被正确初始化,但我不知道我应该做些什么不同的事情。

任何建议都将不胜感激!

这是堆栈跟踪:

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)

这是我的转换器类的缩写版本:

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;
      }
    }
  }

这是单元测试:

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);
    }
}

【问题讨论】:

    标签: java spring unit-testing junit jmock


    【解决方案1】:

    我有同样的问题,我用谷歌搜索但没有答案。我从库中插入源代码,您需要发送内容,无论如何。库可能需要在 skip 方法中检查它是否为 null

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

    在这里发布给其他人

    【讨论】:

      【解决方案2】:
      1. 添加边界条件
      2. 如下生成内容

        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);
        

      文本编码函数

          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】:

        我遇到了同样的问题,经过大量搜索后,我得到了这篇文章,其中我回答了解决我问题的代码。

        Shriprasad 的解决方案适用于文本文件。但是我在使用二进制文件时遇到了一些问题。

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

        【讨论】:

          猜你喜欢
          • 2020-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多