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 をインスタンス化する方法を教えてもらえますか?