15

HibernateValidatorアノテーションでアノテーションを付けたBrowserというPOJOがあります。

import org.hibernate.validator.constraints.NotEmpty;

public class Browser {

    @NotEmpty
    private String userAgent;
    @NotEmpty
    private String browserName;

...

}

Controllerメソッドが検証エラーをキャッチすることを検証しようとする次の単体テストを作成しました。

@Test
public void testInvalidData() throws Exception {
    Browser browser = new Browser("opera", null);
    MockHttpServletRequest request = new MockHttpServletRequest();

    BindingResult errors = new DataBinder(browser).getBindingResult();
    // controller is initialized in @Before method
    controller.add(browser, errors, request);
    assertEquals(1, errors.getErrorCount());
}

これが私のコントローラーのadd()メソッドです:

@RequestMapping(value = "/browser/create", method = RequestMethod.POST)
public String add(@Valid Browser browser, BindingResult result, HttpServletRequest request) throws Exception {
    if (result.hasErrors()) {
        request.setAttribute("errorMessage", result.getAllErrors());
        return VIEW_NAME;
    }

    browserManager.save(browser);

    request.getSession(false).setAttribute("successMessage",
            String.format("Browser %s added successfully.", browser.getUserAgent()));

    return "redirect:/" + VIEW_NAME;
}

私が経験している問題は、結果にエラーが発生しないことです。そのため、@Validが認識されないようです。テストクラスに以下を追加してみましたが、問題は解決しません。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:path-to/WEB-INF/spring-mvc-servlet.xml"})

JUnitでテストするときに@Validが認識(および検証)される方法を知っている人はいますか?

ありがとう、

マット

4

3 に答える 3

6

検証はコントローラーを呼び出す前に行われるため、テストはこの検証を呼び出しません。

コントローラをテストする別のアプローチがあります。この場合、コントローラを直接呼び出さないでください。代わりに、コントローラーがマップされているURLを作成して呼び出します。これを行う方法の良い例を次に示します:http: //rstoyanchev.github.com/spring-31-and-mvc-test/#1

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=WebContextLoader.class, locations = {"classpath:/META-INF/spring/applicationContext.xml", "classpath:/META-INF/spring/applicationContext-test-override.xml", "file:src/main/webapp/WEB-INF/spring/webmvc-config.xml"})
public class MyControllerTest {
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.webApplicationContextSetup(this.wac).build();
}

@Test
@Transactional
public void testMyController() throws Exception {
    this.mockMvc.perform(get("/mycontroller/add?param=1").accept(MediaType.TEXT_HTML))
    .andExpect(status().isOk())
    .andExpect(model().attribute("date_format", "M/d/yy h:mm a"))
    .andExpect(model().attribute("myvalue", notNullValue()))
    .andExpect(model().attribute("myvalue", hasSize(2)))
    .andDo(print());
}
}

POM(春のマイルストーンリポジトリを使用する必要があります):

    <!-- required for spring-test-mvc -->
    <repository>
        <id>spring-maven-milestone</id>
        <name>Spring Maven Milestone Repository</name>
        <url>http://maven.springframework.org/milestone</url>
    </repository>
...
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test-mvc</artifactId>
        <version>1.0.0.M1</version>
        <scope>test</scope>
    </dependency>

注:spring-mvc-testlibはまだ本番環境に対応していません。実装にはいくつかのギャップがあります。春3.2に完全に実装される予定だと思います。

このアプローチは、コントローラーを完全にテストするため、優れたアイデアです。コントローラのマッピングを台無しにするのは簡単なので、これらは実際にユニットテストする必要があります。

于 2012-09-06T21:31:05.567 に答える
2

バリデーターは、呼び出されるコントローラーメソッドの前に、つまり要求をメソッドパラメーターにバインドするプロセス中に呼び出されます。この場合、コントローラーメソッドを直接呼び出すため、バインディングと検証の手順はバイパスされます。

それを機能させる方法は、Spring MVCスタックを介してコントローラーを呼び出すことです-これを行うにはいくつかの方法がありますが、最良の方法は、次のような優れたメカニズムを提供するspring-test-mvcを使用することです。スタックを介して呼び出します。

スタックを呼び出す別の方法は、次の方法でHandlerAdapterをテストに挿入することです。

@Autowired
private RequestMappingHandlerAdapter handlerAdapter;

次に、テストで:

MockHttpServletRequest request = new MockHttpServletRequest("POST","/browser/create");
MockHttpServletResponse response = new MockHttpServletResponse();
httpRequest.addParameter(.... );//whatever is required to create Browser..
ModelAndView modelAndView = handlerAdapter.handle(httpRequest, response, handler);
于 2012-09-06T21:32:03.163 に答える
2

基本的に、でPOJOをインスタンス化し、this.controller = new MyController()そのメソッドを呼び出しましたthis.controller.add(...)。コンテキストのない単純なオブジェクトを持つ単純なJava:@Validは考慮されません。

@ContextConfigurationは、可能なカスタムバリデーターなどを使用して可能なBeanをロードするだけですが、@Validを処理する魔法は実行しません。

必要なのは、コントローラーのaddメソッドへの要求をエミュレートするためのものです。それを完全にエミュレートし、検証を含めます。いくつかのSpringテスト機能(MockHttpServletRequestをインスタンス化するため)を使用したので、そうすることはそう遠くはありませんでした。

Spring 3.0.x以下を使用している場合は、次のことを行う必要があります。

new AnnotationMethodHandlerAdapter()
      .handle(request, new MockHttpServletResponse(), this.controller);

それを機能させるために。

Spring 3.1以降を使用している場合、上記の解決策は機能しません(詳細については、このリンクを参照してください)。次のSpringバージョンに統合されるのを待つ間、このライブラリを使用する必要があります(Springチームからのものなので心配しないでください)。次に、次のようなことをする必要があります

myMockController = MockMvcBuilders.standaloneSetup(new MyController()).build();
myMockController.perform(get("/browser/create")).andExpect(...);

また、Rossen Stoyanchevのこれらの非常に興味深いスライドもご覧ください(ここで説明している部分はスライド#116から始まります)。

注:この種のテストが単体テストまたは統合テストと見なされるかどうかについては、議論に参加しません。リクエストのフルパスをエミュレートするため、これはここで行っている統合テストであると言う人もいます。しかし一方で、Mockitoの@Mockアノテーションのようにコントローラーをモックする(または他のモックフレームワークで同様のことを行う)ことができるので、テストの範囲をほぼ純粋な「単体テスト」に減らすことができると言う人もいます。 。もちろん、代わりに、純粋に古いJava +モックフレームワークを使用してコントローラーを単体テストすることもできますが、この場合、@Valid検証をテストすることはできません。あなたの選択をしてください !:)

于 2012-09-06T21:33:17.717 に答える