2014-09-26 34 views
3

我試圖按照這篇文章[1]來模擬我的Spring MvcMock測試中的安全性。使用自定義UserDetails實現測試Spring Security和MvcMock

REST服務我想測試看起來是這樣的:

@RequestMapping(value = "/something/{id}", method = RequestMethod.DELETE) 
public ResponseEntity<Void> deleteXXX(@ActiveUser AppUser user, @PathVariable(value = "id") Long id) { 
    ... 
} 

其中@ActiveUser是一個自定義實現/擴展@AuthenticationPrincipalAppUser是自定義UserDetails實施。

在測試中我這樣做:

mockMvc.perform(delete("/something/{i}", "123").with(user(new AppUser(...)))); 

我還添加了一些TestExecutionLIsteners

@TestExecutionListeners(listeners = { ServletTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, WithSecurityContextTestExecutionListener.class }) 

```

但它失敗:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.corp.AppUser]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.corp.AppUser.<init>() 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973) 
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:885) 

這是可以的,如AppUser沒有默認的構造函數,但框架實際上不應該創建用戶,而是使用我傳入測試的那個。

要在運行期間解決此問題,我必須將AuthenticationPrincipalArgumentResolver作爲HandlerMethodArgumentResolver添加到Web配置中,但是如何在測試用例中執行此操作?

有沒有這方面的工作示例?

[1] https://spring.io/blog/2014/05/23/preview-spring-security-test-web-security

編輯:

的TestClass中和它的配置是這樣的:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = { MyControllerTest.DummyAppConfig.class, MyControllerTest.DummySecurityConfiguration.class }) 
@TestExecutionListeners(listeners = { ServletTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class, WithSecurityContextTestExecutionListener.class }) 
@WebAppConfiguration 
public class MyControllerTest { 


@Test 
public void doTest() throws Exception { 
    mockMvc.perform(delete("/something/{i}", "123").with(user(new AppUser(...)))); 
} 


@Configuration 
public static class DummyAppConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { 
     argumentResolvers.add(new AuthenticationPrincipalArgumentResolver()); 
} 

    @Bean 
    public MyController aController() { 
     return new MyController(); 
    } 

} 

@Configuration 
@EnableWebSecurity 
public static class DummySecurityConfiguration extends WebSecurityConfigurerAdapter { 
} 

```

這是完整的堆棧跟蹤:

```

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.corp.AppUser]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.corp.AppUser.<init>() 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973) 
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:885) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:694) 
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:770) 
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:145) 
at com.corp.ControllerTest.doTest(RestCorporateAccountSearchProfilesControllerTest.java:231) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:606) 
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:72) 
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81) 
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82) 
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:60) 
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67) 
at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162) 
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.corp.AppUser]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.corp.AppUser.<init>() 
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:107) 
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:138) 
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:81) 
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:104) 
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79) 
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157) 
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124) 
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:781) 
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721) 
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83) 
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943) 
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877) 
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961) 
... 39 more 
Caused by: java.lang.NoSuchMethodException: com.corp.AppUser.<init>() 
at java.lang.Class.getConstructor0(Class.java:2800) 
at java.lang.Class.getDeclaredConstructor(Class.java:2043) 
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:104) 
... 52 more 

```

+0

安全配置是什麼樣的?你在使用@EnableWebMvcSecurity嗎?也請提供完整的堆棧跟蹤。 – 2014-09-29 16:41:34

+0

我添加了堆棧跟蹤和配置(嵌入在測試用例中) – domi 2014-09-30 09:37:13

+0

構建器@ActiveUser AppUser user嘗試用'SecurityContextHolder.getContext()創建'user'。getAuthentication()getPrincipal()'。你有沒有給認證一個實現'Authentication'的對象,並在其'getPrincipal()'方法中返回一個'AppUser'? – 2014-09-30 11:48:27

回答

2

如果使用MockMvcBuilders.standaloneSetup()方法,你可以解析器添加到獨立MockMvc像這樣:

MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new AuthenticationPrincipalArgumentResolver()).build() 

我也有麻煩它與MockMvcBuilders.webAppContextSetup()方法工作,但獨立的工作沒有關心。

+0

這似乎解決了這個例外,發佈後,但現在我看到我的自定義UserDetails對象進入我的控制器作爲null。不要以爲你會有任何建議嗎? – akokskis 2015-10-23 03:00:50

+0

http://stackoverflow.com/questions/33294769/spring-security- test-and-mockmvc-supply-null-custom-userdetails-parameter-to-res有關更多詳細信息。 – akokskis 2015-10-23 04:15:08

0

您需要,以獲得Spring Security的/ MVC整合上DummySecurityConfiguration使用@EnableWebMvcSecurity。見http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#mvc-enablewebmvcsecurity

+0

仍然是完全相同的錯誤... btw。我正在使用spring-security-test:4.0.0.M2 with spring-webmvc:4.1.0.RELEASE – domi 2014-09-30 15:14:34

+0

你有沒有在任何版本庫中運行的例子,例如Spring中的testcase? – domi 2014-10-10 13:34:22

相關問題