3

複数のファイルをアップロードするためのスプリング コントローラーをテストしようとしています。コントローラーは次のとおりです。

@RequestMapping("/vocabularys")
@Controller
public class VocabularyController {
...

テストしたいアクション:

@RequestMapping(value = "/import", method = {RequestMethod.PUT, RequestMethod.POST})
@ResponseBody
@CacheEvict(value="vocabulary", allEntries=true)
public Object importVocabulary(MultipartHttpServletRequest request, HttpServletResponse response) {
...

webmvc-config.xml にあるリゾルバー:

<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"/>

コードは問題なく動作します。これを単体/統合テストしようとすると、問題が発生します。

テストでの私の試みは次のとおりです。

public class VocabularyControllerTest extends BaseControllerTest {

    static final private String AdminUsername = "administrator";

    @Test
    public void shouldBeAbleToUploadAFile() throws Exception {
        createTestWorkspace();
        login(AdminUsername, "*");

        MockMultipartFile file = new MockMultipartFile("test_vocab.xml", new FileInputStream("src/test/files/acme_vocabulary.xml"));
        MockMultipartHttpServletRequestBuilder mockMultipartHttpServletRequestBuilder = (MockMultipartHttpServletRequestBuilder) fileUpload("/vocabularys/import").accept(MediaType.ALL).session(httpSession);
        mockMultipartHttpServletRequestBuilder.file(file);
        mockMultipartHttpServletRequestBuilder.content("whatever");

        ResultActions resultActions = mockMvc.perform(mockMultipartHttpServletRequestBuilder);

        resultActions.andExpect(status().isFound());
    }
}

createWorkspace()andなどは無視してlogin()ください。これらは、セキュリティ フィルターを通過するためのものです。

の関連部分BaseControllerTest:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextHierarchy({
    @ContextConfiguration(locations = {
        "file:src/test/resources/META-INF/spring/applicationContext.xml",
        "file:src/test/resources/META-INF/spring/applicationContext-security.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-database.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-activiti.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-cache.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-jms.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-mail.xml",
        "file:src/main/resources/META-INF/spring/applicationContext-mongo.xml"}),
    @ContextConfiguration(locations = {
        "file:src/main/webapp/WEB-INF/spring/webmvc-config.xml",
        "file:src/test/webapp/WEB-INF/spring/applicationContext-filters.xml"})
})
@Transactional
public class BaseControllerTest extends BaseTest {

    @Autowired
    WebApplicationContext wac;
    @Autowired
    MockHttpSession httpSession;
    @Autowired
    MockServletContext servletContext;
    @Autowired
    OpenEntityManagerInViewFilter openEntityManagerInViewFilter;
    @Autowired
    HiddenHttpMethodFilter hiddenHttpMethodFilter;
    @Autowired
    CharacterEncodingFilter characterEncodingFilter;
    @Autowired
    SessionFilter sessionFilter;
    @Autowired
    WorkflowAsSessionFilter workflowAsSessionFilter;
    @Autowired
    FilterChainProxy springSecurityFilterChain;
    @Autowired
    RequestFilter requestFilter;
    MockMvc mockMvc;

    protected static final String TestFileDir = "src/test/files/";

    @Before
    public void setUp() throws Exception {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
                .addFilter(openEntityManagerInViewFilter, "/*")
                .addFilter(hiddenHttpMethodFilter, "/*")
                .addFilter(characterEncodingFilter, "/*")
                .addFilter(sessionFilter, "/*")
                .addFilter(workflowAsSessionFilter, "/*")
                .addFilter(springSecurityFilterChain, "/*")
                .addFilter(requestFilter, "/*")
                .build();

        servletContext.setContextPath("/");

        Session session = Session.findBySessionId(httpSession.getId());
        if (session == null) {
            session = new Session();
            session.setJsessionid(httpSession.getId());
            session.persist();
        }
    }
...

問題は、これをデバッグしようとするとperform、オブジェクトに対するアクションがmockMvcコントローラー メソッドにヒットしないことです。セキュリティ フィルターを通過するのが問題だと思っていましたが (これが と をすべて持っている理由loginです)、ボキャブラリ コントローラーで他のアクションをテストしたところ、問題なくヒットすることができました。

考え?アイデア?提案?

4

2 に答える 2

3

問題が見つかりました。

Springは最終的MockMultipartHttpServletRequestBuilderにオブジェクトを返します。MockHttpMultipartServletRequest

CommonsMultipartResolverただし、ブラウザーが行うことは、XML で定義された Bean によって取得および解析されるマルチパート エンコードされた要求を投稿することです。

ただし、テストでは、既に を投稿しているMockHttpMultipartServletRequestため、リゾルバーにこれを解析させたくないため、リゾルバーが起動しないプロファイルを用意するだけで済みます。

しかし、私たちが選択したのは、MockHttpServletRequestマルチパート エンコーディングを持つ を構築し、それを Spring フィルターに通すことで、リゾルバーが起動する統合テストもできるようにすることです。

残念ながら、Spring テスト ライブラリにはサポート/ヘルパーがありません。これにより、MockHttpServletRequestandaddPart()を取得したり、その効果を得ることができます => ハンドコーディングされたブラウザー エミュレーション関数 :(

于 2013-10-02T17:45:34.080 に答える
2

マルチパート アップロードをテストする簡単な方法は、StandardServletMultipartResolver を使用することです。テストには、次のコードを使用します。

    final MockPart profilePicture = new MockPart("profilePicture", "stview.jpg", "image/gif", "dsdsdsd".getBytes());
    final MockPart userData = new MockPart("userData", "userData", "application/json", "{\"name\":\"test aida\"}".getBytes());

    this.mockMvc.perform(
            fileUpload("/endUsers/" + usr.getId().toString()).with(new RequestPostProcessor() {

                @Override
                public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
                    request.addPart(profilePicture);
                    request.addPart(userData);
                    return request;
                }
            }) 

MockPart クラス

public class MockPart extends MockMultipartFile implements Part {

private Map<String, String> headers;

public MockPart(String name, byte[] content) {
    super(name, content);
    init();
}

public MockPart(String name, InputStream contentStream) throws IOException {
    super(name, contentStream);
    init();
}

public MockPart(String name, String originalFilename, String contentType, byte[] content) {
    super(name, originalFilename, contentType, content);
    init();
}

public MockPart(String name, String originalFilename, String contentType, InputStream contentStream) throws IOException {
    super(name, originalFilename, contentType, contentStream);
    init();
}

public void init() {
    this.headers = new HashMap<String, String>();
    if (getOriginalFilename() != null) {
        this.headers.put("Content-Disposition".toLowerCase(), "form-data; name=\"" + getName() + "\"; filename=\"" + getOriginalFilename() + "\"");
    } else {
        this.headers.put("Content-Disposition".toLowerCase(), "form-data; name=\"" + getName() + "\"");
    }
    if (getContentType() != null) {
        this.headers.put("Content-Type".toLowerCase(), getContentType());
    }
}

@Override
public void write(String fileName) throws IOException {
}

@Override
public void delete() throws IOException {
}

@Override
public String getHeader(String name) {
    return this.headers.get(name.toLowerCase());
}

@Override
public Collection<String> getHeaders(String name) {
    List<String> res = new ArrayList<String>();
    if (getHeader(name) != null) {
        res.add(getHeader(name));
    }
    return res;
}

@Override
public Collection<String> getHeaderNames() {
    return this.headers.keySet();
}

}

于 2014-07-09T13:48:35.930 に答える