2017-01-11 14 views
0

私は残りのAPIを作成しています。最近、私はプロジェクトに基本認証を追加しましたので、同様の構成指定されている:BasicAuth onとカスタムWebSecurityConfigurerAdapterを使用したSpringテストコントローラ

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    public final static String ROLE_ADMIN = "ADMIN"; 
    public final static String ROLE_USER = "USER"; 

    /** 
    * Determines the resource access for different account types 
    */ 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 

     http 
       .authorizeRequests() 
        .antMatchers("/user/create").permitAll() 
        .antMatchers("/admin/**").hasRole(ROLE_ADMIN) 
        .anyRequest().authenticated() 
       .and() 
        .csrf().disable() 
        .httpBasic(); 
    } 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(inMemoryUserDetailsManager()); 
    } 

    /** 
    * Initially fills Spring Security with default accounts 
    */ 
    @Bean 
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() { 

     final Properties users = new Properties(); 
     users.put("user","pass,ROLE_USER,enabled"); //login = user, password = pass 
     users.put("admin","pass,ROLE_ADMIN,enabled"); //login = admin, password = pass 
     return new InMemoryUserDetailsManager(users); 
    } 
} 

は、私も彼らのためにいくつかのコントローラといくつかのテストをした:

コントローラ:

@RestController 
public class MovieController { 

    @Autowired @Qualifier("MovieService")//not relevant 
    private MovieService ms; 

    @Autowired @Qualifier("CastService")//not relevant 
    private CastService cs; 

    @RequestMapping(value = "admin/movies", method = GET) 
    public List<Movie> selectAllMovies(){ 

     return ms.selectAll(); 
    } 

//the rest of the code.. 
} 

をとテスト:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@Transactional 
public class MovieControllerTest { 

    @Mock 
    private MovieService movieService; 

    @Mock 
    private CastService castService; 

    @Mock 
    private ActorService actorService; 

    @Mock 
    private UserService userService; 

    @InjectMocks 
    private MovieController movieController; 

    private MockMvc mvc; 

    @Before 
    public void setUp(){ 

     MockitoAnnotations.initMocks(this); 

     mvc = MockMvcBuilders.standaloneSetup(movieController).build(); 
    } 

    @Test 
    @WithMockUser(roles = "ADMIN", username = "admin", password = "pass") 
    @WithUserDetails("admin") 
    public void testGetAllMovies() throws Exception { 

     List<Movie> movieList = Arrays.asList(
       new Movie("title1", "desc1", MovieType.newest, 10f, true), 
       new Movie("title2", "desc2", MovieType.newest, 10f, true), 
       new Movie("title3", "desc3", MovieType.newest, 10f, true)); 

     when(movieService.selectAll()).thenReturn(movieList); 

     String uri = "admin/movies"; 

     MvcResult result = mvc.perform(MockMvcRequestBuilders.get(uri) 
       .accept(MediaType.APPLICATION_JSON)).andReturn(); 

     String content = result.getResponse().getContentAsString(); 
     int status = result.getResponse().getStatus(); 

     verify(movieService, times(1)).selectAll(); 

     Assert.assertEquals("failure - expected HTTP status 200", 200, status); 
     Assert.assertTrue("failure - expected HTTP response body to have a value", content.trim().length() > 0); 
    } 

//the rest of the code.. 
} 

しかし、私がテストを実行すると、私はエラーをMockitoから言う:

Wanted but not invoked: 
movieService.selectAll(); 
-> at com.myproject.Controller.MovieControllerTest.testGetAllMovies(MovieControllerTest.java:87) 
Actually, there were zero interactions with this mock. 

春のセキュリティでは、テストで認証が必要なURL( "admin/movies")を呼び出すことはできないようです。設定ファイルで指定されているため、このURLにはADMINロールが必要です。面白いのは、コントローラのURLの「管理者」の部分を削除してテストすると、テストが機能します!しかし、configによると、それはまだUSERロール(あなたがconfigで見ることができるように、 "/ user/create"だけがそれを必要とする)で認証する必要があります。

私は@WithMockUser(username="admin", password="pass", roles="ADMIN")を使用しようとしましたが、それは役に立たず、エラーは同じです。

答えて

0

なぜMVCテストにMockitoを使用しますか?これは奇妙なことですか?通常は、実際のコントローラ/サービス/リポジトリを直接テストに@入力します。

MVCテストの基本クラスの外観は次のとおりです。あなたがMovkMvcを使用する場合

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(loader = AnnotationConfigWebContextLoader.class, classes = IntegrationTestConfiguration.class) 
@WebAppConfiguration 
public abstract class IntegrationTest { 
    // from some Spring context 
    @Autowired 
    protected HttpClientConnectionManager connectionManager; 

    @Autowired 
    protected ClientDetailsService clientDetailsService; 

    @Autowired 
    protected WebApplicationContext context; 

    @SuppressWarnings("SpringJavaAutowiringInspection") // this is created by Spring Security 
    @Autowired 
    protected FilterChainProxy filterChain; 

    private MockMvc mvc; 

    protected TestSession.LoginDetails integrationTestUserDetails; 

    @Before 
    public void configureMock() throws InvalidDecryptionKeyException { 
     // setup spring MVC 
     MockHttpServletRequestBuilder requestBuilder = get("/"); 
     requestBuilder.secure(true); 
     requestBuilder.header("origin", "http://localhost"); 
     mvc = MockMvcBuilders 
       .webAppContextSetup(context) 
       .apply(SecurityMockMvcConfigurers.springSecurity()) 
       .addFilter(filterChain) 
       .defaultRequest(requestBuilder) 
       .build(); 
    } 

} 

はまた、あなたはサーブレットコンテナはHttpServletRequestのにバイトストリームを処理した時点で、ただのHttp上のレベルで通信していることを覚えておいてください。つまり、JSONをポストすると、通常はJavaオブジェクトを作成し、このようなバイトにシリアル化します。

mvc.perform(post("/internal/signOut") 
    .session(mySession) 
    .content(objectMapper.writeValueAsString(signOutRequest)))); 
+0

ちょっと、私はちょうどそれに精通してMockitoを使用しています。とにかく、あなたの答えをありがとうが、私は私のばかげた問題に解決策を見つけたようだ:)私のポストを参照してください。 –

0

いいので、Spring Securityは私の問題とは関係がないようです。 mockitoがmockとのやりとりを検出できない本当の理由(コントローラは決して相互作用しませんでした)は、私がMockMvcRequestBuilderに入れたURLが間違っていたことでした。偶然、私は、urlがurl文字列の先頭にスラッシュを含む必要があることを発見したので、私は変更しました:"admin/movies""/admin/movies"に変更しても、上のコードで見るように、コントローラのマッピングにはスラッシュ( "admin/movies")はありません。 クレイジーですが、本当です:)

関連する問題