web-dev-qa-db-fra.com

Comment PUT multipart / form-data en utilisant Spring MockMvc?

J'ai une méthode de contrôleur avec une méthode PUT, qui reçoit des données multipart/form:

   @RequestMapping(value = "/putIn", method = RequestMethod.PUT)
   public Foo updateFoo(HttpServletRequest request,
                           @RequestBody Foo foo,
                           @RequestParam("foo_icon") MultipartFile file) {
    ...
   }

et je veux le tester en utilisant MockMvc. Malheureusement MockMvcRequestBuilders.fileUpload crée essentiellement une instance de MockMultipartHttpServletRequestBuilder qui a une méthode POST:

super(HttpMethod.POST, urlTemplate, urlVariables)

MODIFIER: Je peux certainementje ne peux pas créer ma propre implémentation de MockHttpServletRequestBuilder, disons

public MockPutMultipartHttpServletRequestBuilder(String urlTemplate, Object... urlVariables) {
    super(HttpMethod.PUT, urlTemplate, urlVariables);
    super.contentType(MediaType.MULTIPART_FORM_DATA);
}

parce que MockHttpServletRequestBuilder a un constructeur package-local.

Mais je me demande si c'est plus pratique Est-il possible de le faire, est-ce que j'ai raté une classe ou une méthode existante pour le faire?

19
Andremoniy

Oui, il y a un moyen, et c'est simple aussi!

J'ai moi-même rencontré le même problème. Bien que j'étais découragé par la réponse de Sam Brannen, il semble que Spring MVC supporte de nos jours le téléchargement de fichiers PUT car je pouvais simplement faire une telle demande en utilisant Postman (j'utilise Spring Boot 1.4.2). Donc, j'ai continué à creuser et j'ai trouvé que le seul problème était le fait que MockMultipartHttpServletRequestBuilder renvoyé par MockMvcRequestBuilders.fileUpload() avait la méthode codée en dur sur "POST". J'ai ensuite découvert la méthode with() ...

et cela m'a permis de trouver cette astuce pour forcer le MockMultipartHttpServletRequestBuilder à utiliser la méthode "PUT" de toute façon:

    MockMultipartFile file = new MockMultipartFile("data", "dummy.csv",
            "text/plain", "Some dataset...".getBytes());

    MockMultipartHttpServletRequestBuilder builder =
            MockMvcRequestBuilders.fileUpload("/test1/datasets/set1");
    builder.with(new RequestPostProcessor() {
        @Override
        public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
            request.setMethod("PUT");
            return request;
        }
    });
    mvc.perform(builder
            .file(file))
            .andExpect(status().ok());

Fonctionne comme un charme!

37
HammerNL

Ceci n'est malheureusement pas actuellement pris en charge dans Spring MVC Test, et je ne vois pas d'autre solution que de créer votre propre MockPutMultipartHttpServletRequestBuilder et de copier-coller le code personnalisé à partir de l'implémentation standard.

Pour ce que ça vaut, Spring MVC ne prend pas non plus en charge les demandes de téléchargement de fichiers PUT par défaut. Les résolveurs multiparties sont codés en dur pour accepter uniquement les demandes de téléchargement de fichiers POST - à la fois pour Apache Commons et la prise en charge de l'API Servlet standard.

Si vous souhaitez que Spring prenne en charge PUT en plus, n'hésitez pas à ouvrir un ticket dans l'outil de suivi des problèmes JIRA de Spring.

4
Sam Brannen

Vous pouvez transmettre à la fois foo et file

Essayez de réécrire votre contrôleur comme:

@RequestMapping(value = "/putIn", method = RequestMethod.PUT)
public Foo updateFoo(
    HttpServletRequest request,
    @RequestPart Foo foo,
    @RequestPart MultipartFile file) {
    ...
}

Et le test ressemble à:

    MockMultipartFile file = new MockMultipartFile("file", "dummy.csv",
            "text/plain", "Some dataset...".getBytes());
    // application/json if you pass json as string
    MockMultipartFile file2 = new MockMultipartFile("foo", "foo.txt",
            "application/json", "Foo data".getBytes());

    MockMultipartHttpServletRequestBuilder builder =
            MockMvcRequestBuilders.multipart("/test1/datasets/set1");
    builder.with(new RequestPostProcessor() {
        @Override
        public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
            request.setMethod("PUT");
            return request;
        }
    });
    mvc.perform(builder
            .file(file)
            .file(file2))
            .andExpect(status().ok());
0
lalilulelo_1986