spring @MVCアノテーションのテスト
-
22-09-2019 - |
質問
先日、@validアノテーションがコントローラークラスから誤って削除された問題に遭遇しました。残念ながら、それは私たちのテストを壊しませんでした。私たちのユニットテストはどれも実際に春を行使しません AnnotationMethodHandlerAdapter
小道。コントローラーのクラスを直接テストするだけです。
@MVCアノテーションが間違っている場合、正しく失敗するユニットまたは統合テストを書くにはどうすればよいですか? springに、関連するコントローラーをmockhttpservletなどで見つけて行使するように依頼する方法はありますか?
解決
今後の春3.2(スナップショットが利用可能)またはスプリングテストmvc(https://github.com/springsource/spring-test-mvc)では、次のように行うことができます。
最初に検証をエミュレートして、検証器をテストしたくないので、検証が呼び出されたかどうかを知りたいだけです。
public class LocalValidatorFactoryBeanMock extends LocalValidatorFactoryBean
{
private boolean fakeErrors;
public void fakeErrors ( )
{
this.fakeErrors = true;
}
@Override
public boolean supports ( Class<?> clazz )
{
return true;
}
@Override
public void validate ( Object target, Errors errors, Object... validationHints )
{
if (fakeErrors)
{
errors.reject("error");
}
}
}
これは私たちのテストクラスです:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class RegisterControllerTest
{
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Autowired
@InjectMocks
private RegisterController registerController;
@Autowired
private LocalValidatorFactoryBeanMock validator;
@Before
public void setup ( )
{
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// if you want to inject mocks into your controller
MockitoAnnotations.initMocks(this);
}
@Test
public void testPostValidationError ( ) throws Exception
{
validator.fakeErrors();
MockHttpServletRequestBuilder post = post("/info/register");
post.param("name", "Bob");
ResultActions result = getMockMvc().perform(post);
// no redirect as we have errors
result.andExpect(view().name("info/register"));
}
@Configuration
@Import(DispatcherServletConfig.class)
static class Config extends WebMvcConfigurerAdapter
{
@Override
public Validator getValidator ( )
{
return new LocalValidatorFactoryBeanMock();
}
@Bean
RegisterController registerController ( )
{
return new RegisterController();
}
}
}
他のヒント
私はこの種のことのために統合テストを書きます。検証注釈付きのBeanを持っているとします:
public class MyForm {
@NotNull
private Long myNumber;
...
}
提出物を処理するコントローラー
@Controller
@RequestMapping("/simple-form")
public class MyController {
private final static String FORM_VIEW = null;
@RequestMapping(method = RequestMethod.POST)
public String processFormSubmission(@Valid MyForm myForm,
BindingResult result) {
if (result.hasErrors()) {
return FORM_VIEW;
}
// process the form
return "success-view";
}
}
そして、@validおよび@notnullアノテーションが正しく配線されていることをテストしたいと思います。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:web/WEB-INF/application-context.xml",
"file:web/WEB-INF/dispatcher-servlet.xml"})
public class MyControllerIntegrationTest {
@Inject
private ApplicationContext applicationContext;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
@Before
public void setUp() throws Exception {
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
}
ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
final HandlerExecutionChain handler = handlerMapping.getHandler(request);
assertNotNull("No handler found for request, check you request mapping", handler);
final Object controller = handler.getHandler();
// if you want to override any injected attributes do it here
final HandlerInterceptor[] interceptors =
handlerMapping.getHandler(request).getInterceptors();
for (HandlerInterceptor interceptor : interceptors) {
final boolean carryOn = interceptor.preHandle(request, response, controller);
if (!carryOn) {
return null;
}
}
final ModelAndView mav = handlerAdapter.handle(request, response, controller);
return mav;
}
@Test
public void testProcessFormSubmission() throws Exception {
request.setMethod("POST");
request.setRequestURI("/simple-form");
request.setParameter("myNumber", "");
final ModelAndView mav = handle(request, response);
// test we're returned back to the form
assertViewName(mav, "simple-form");
// make assertions on the errors
final BindingResult errors = assertAndReturnModelAttributeOfType(mav,
"org.springframework.validation.BindingResult.myForm",
BindingResult.class);
assertEquals(1, errors.getErrorCount());
assertEquals("", errors.getFieldValue("myNumber"));
}
私のブログ投稿をご覧ください SpringのMVCアノテーションの統合テスト
もちろん。あなたのテストが独自にインスタンス化できない理由はありません DispatcherServlet
, 、コンテナにあるさまざまなアイテムを注入します(例: ServletContext
)、コンテキスト定義ファイルの場所を含む。
春には、さまざまなサーブレット関連が付属しています MockXYZ
この目的のためのクラス MockServletContext
, MockHttpServletRequest
と MockHttpServletResponse
. 。彼らは通常の意味で実際に「モック」オブジェクトではなく、愚かなスタブのようなものですが、仕事をします。
サーブレットのテストコンテキストには、通常のMVC関連の豆と、テストする豆があります。サーブレットが初期化されたら、模擬リクエストと応答を作成し、サーブに供給します service()
方法。リクエストが正しくルーティングされた場合、モック応答に書き込まれた結果を確認できます。