0

zip ファイルを読み取り、すべてのエントリを処理するマルチパート コントローラーをテストしたいと考えています。これを行うコントローラーメソッドは次のとおりです。

@RequestMapping(value = "/content/general-import", method = RequestMethod.POST)
public ModelAndView handleGeneralUpload(
                                  @RequestParam("file") MultipartFile file) throws IOException {

    String signature = "RETAILER_GROUP:*|CHANNEL:*|LOCALE:de-AT|INDUSTRY:5499";

    LOG.info("Processing file archive: {} with signature: {}.", file.getName(), signature);

    ModelAndView mav = new ModelAndView();
    mav.setViewName("contentUpload");

    if (!file.isEmpty()) {
        byte[] bytes = file.getBytes();

        ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));

        ZipEntry entry = null;
        while ((entry = zis.getNextEntry()) != null) {

            // process each file, based on what it is and whether its a directory etc.
            if (!entry.isDirectory()) {
                // if the entry is a file, extract it
                LOG.debug("Processing entry: {}",entry.getName());

                int length = (int) entry.getSize();

                Content contentToSave = null;
                if(entry.getName().contains("gif")) {
                    contentToSave = Content.makeImage(entry.getName(), Content.GIF, signature, getBytesFrom(zis, "gif"));
                } else if (entry.getName().contains("png")) {
                    contentToSave = Content.makeImage(entry.getName(), Content.PNG, signature, getBytesFrom(zis, "png"));
                } else if (entry.getName().contains("jpeg")) {
                    contentToSave = Content.makeImage(entry.getName(), Content.JPEG, signature, getBytesFrom(zis, "jpeg"));
                } else if (entry.getName().contains("json")) {
                    contentToSave = Content.makeFile(entry.getName(), Content.JSON, signature, getStringFrom(zis, length));
                } else if (entry.getName().contains("js")) {
                    contentToSave = Content.makeFile(entry.getName(), Content.JS, signature, getStringFrom(zis, length));
                } else if (entry.getName().contains("css")) {
                    contentToSave = Content.makeFile(entry.getName(), Content.CSS, signature, getStringFrom(zis, length));
                }

                Content contentAleadyThere = contentService.fetch(entry.getName());
                if(contentAleadyThere != null) {
                    LOG.warn("Replacing file: {} with uploaded version.", contentToSave.getName());
                }

                contentService.put(contentToSave);
                LOG.info("Persisted file: {} from uploaded version.", contentToSave.getName());
            }

        }


        mav.addObject("form", UploadViewModel.make("/content/general-import", "Updated content with file"));

        return mav;
    } else {

        mav.addObject("form", UploadViewModel.make("/content/general-import", "Could not update content with file"));

        return mav;
    }
}

関連するテストは次のようになります。

@Test public void testProcessingGeneralUpload() throws Exception {

Resource template = wac.getResource("classpath:lc_content/content.zip");

MockMultipartFile firstFile = new MockMultipartFile(
        "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, template.getInputStream());

MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.fileUpload("/content/general-import")
        .file(firstFile))
        .andExpect(status().isOk())
        .andExpect(view().name("contentUpload"))
        .andExpect(model().attributeExists("form")).andReturn();

// processing assertions
ModelMap modelMap = mvcResult.getModelAndView().getModelMap();
Object object = modelMap.get("form");
    assertThat(object, is(not(nullValue())));
    assertThat(object, is(instanceOf(UploadViewModel.class)));
UploadViewModel addModel = (UploadViewModel) object;
    assertThat(addModel.getMessage(), is(notNullValue()));
assertThat(addModel.getPostUrl(), is(notNullValue()));
assertThat(addModel.getPostUrl(), is("/content/general-import"));
assertThat(addModel.getMessage(), is("Updated content with file"));

// persistence assertions

}

私が得るエラーは次のとおりです。

java.io.IOException: Stream closed
    at java.util.zip.ZipInputStream.ensureOpen(ZipInputStream.java:67)
    at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:116)
    at com.touchcorp.touchpoint.resource.mvc.ContentUploadResource.handleGeneralUpload(ContentUploadResource.java:221)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:62)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:170)
    at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:137)
    at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:141)
    at com.touchcorp.touchpoint.resource.mvc.ContentUploadResourceUnitTest.testProcessingGeneralUpload(ContentUploadResourceUnitTest.java:190)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

問題と思われるのは、正しい状態で MockMultipartFile を構築できないように見えることです。回避策の 1 つは、すべての処理ロジックを別のメソッドにリファクタリングし、コンテナー外でテストすることだと思いますが、ロジックをすべて 1 か所にまとめておきたいと思います。content.zip を読み取れるように MockMultipartFile をインスタンス化する方法を教えてもらえますか?

4

1 に答える 1

2

答えが見つかりました。次の行を置き換える必要がありました。

MockMultipartFile firstFile = new MockMultipartFile(
        "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, template.getInputStream());

と:

MockMultipartFile firstFile = new MockMultipartFile(
     "file", "filename.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, new ZipInputStream(template.getInputStream()));

ただし、新しい問題があります。ファイルが空です。つまり、コントローラーの file.isEmpty() が true を返します。

編集

これにも答えがあります。行を次のように置き換えました。

MockMultipartFile firstFile = new MockMultipartFile(
            "file", "content.zip", MediaType.APPLICATION_OCTET_STREAM_VALUE, extractFile(template.getFile()));

ここで、extractFile は次のとおりです。

private byte[] extractFile(File zipFile) throws IOException {

    ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile));
    System.out.println("length of file: " + zipFile.length());

    byte[] output = null;

    try {
        byte[] data = new byte[(int)zipFile.length()];
        zipIn.read(data);
        zipIn.close();

        output = data;
    } catch (IOException e) {
        e.printStackTrace();
    }
    return output;
}

バイトを埋めるために、ストリームからすべてのデータを読み込む必要があるようです。ただし、まだ解決されていませんが、以下を参照してください: Spring mvc multipartfile から zipinputstream に移動して、それに関する議論を行う方法。

于 2014-06-26T01:55:00.863 に答える