7 votes

Les tests unitaires avec MockMultipartHttpServletRequest (soulèvent une NullPointerException dans ItemInputStream.makeAvailable)

J'ai écrit une classe transformateur qui prend un HttpServletRequest et le transforme en un autre type qui contient un pointeur vers le InputStream de la requête servlet. (L'idée est d'abstraire le protocole de transport entrant de la gestion de la requête, donc je pourrais également écrire un transformateur similaire à partir du FTP, par exemple.)

Maintenant, j'essaie d'écrire un test unitaire pour cela, et j'ai des problèmes. J'ai réussi à trouver le bon modèle de base pour créer une requête HTTP multipart valide (en utilisant les classes Spring MockMultipartHttpServletRequest et MockMultipartFile), mais maintenant j'obtiens une NullPointerException dans la méthode initialize() de ma classe UploadRequest. Je suppose que le problème est que d'une manière ou d'une autre le flux à l'intérieur de MockMultipartHttpServletRequest n'est pas initialisé correctement, mais je ne peux pas comprendre ce que je devrais faire différemment.

Toute suggestion serait grandement appréciée!

Voici la trace de la pile :

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.(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)

Voici une version abrégée de ma classe transformateur :

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

  public UploadRequest()
  {
    params = new HashMap();
  }

  public void initialize(HttpServletRequest sRequest, 
                         ServletFileUpload upload)
    throws IOException, FileUploadException
  {
    Enumeration 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;
      }
    }
  }

Et voici le test unitaire :

import org.springframework.mock.web.MockMultipartHttpServletRequest;
import org.springframework.mock.web.MockMultipartFile;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
// etc.... autres 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);
    }
}

2voto

Ben zhang Points 21

J'ai le même problème et j'ai cherché sur Google mais aucune réponse. J'ai branché le code source de la bibliothèque. Vous devez envoyer du contenu, peu importe. La bibliothèque doit vérifier si c'est nul dans la méthode skip

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

Publié ici pour les autres

1voto

Shriprasad Points 31
  1. Ajouter la condition de limite
  2. Générer le contenu comme suit

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

Fonction pour encoder du texte

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

1voto

Samuel Points 1141

J'ai rencontré le même problème, après avoir beaucoup cherché, j'ai trouvé ce post dans lequel j'ai répondu avec du code qui a résolu mon problème.

La solution de Shriprasad fonctionne bien pour les fichiers texte. Mais j'ai eu quelques problèmes avec les fichiers binaires.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X