2016-10-16 12 views
2

Spring Securityで実装された認証フィルタをSpringブートでテストするための統合テストを実装したいと考えています。しかし...私は...失われていますSpringブートによる認証フィルタの統合テスト

まず、ここで私の「生産」の実装です:

@EnableWebSecurity 
public class SecurityConfigurer extends WebSecurityConfigurerAdapter { 
    @Autowired 
    private IdentityService loginService; 
    @Autowired 
    private PersonService personService; 

    @Override 
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(loginService).passwordEncoder(new BCryptPasswordEncoder()); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.authorizeRequests().antMatchers(PATH_LOGIN).permitAll(); 
     http.authorizeRequests().antMatchers("/**").fullyAuthenticated(); 

     http.addFilterBefore(new AuthenticationFilter(PATH_LOGIN, authenticationManager(), personService), 
      UsernamePasswordAuthenticationFilter.class); 
    } 

:私は私のウェブコンフィギュラアダプタ私のフィルタを認証マネージャを作成し、宣言を持っている

次に、ここで私のフィルタの実装です:今

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

    private ObjectMapper objectMapper = new ObjectMapper(); 

    private PersonService personService; 

    protected AuthenticationFilter(String loginPath, AuthenticationManager authenticationManager, 
     PersonService personService) { 
     super(loginPath); 
     this.personService = personService; 
     setAuthenticationManager(authenticationManager); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 
     throws AuthenticationException, IOException, ServletException { 

     LoginInfo loginInfo = objectMapper.readValue(request.getInputStream(), LoginInfo.class); 
     UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
      loginInfo.getUsername(), loginInfo.getPassword()); 

     Authentication authentication = getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken); 
     SecurityContextHolder.getContext().setAuthentication(authentication); 

     return authentication; 

    } 

    @Override 
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, 
     Authentication authResult) throws IOException, ServletException { 
     Identity identity = (Identity) authResult.getPrincipal(); 

     Person person = personService.getPersonByMail(identity.getUsername()); 

     UserInfo userInfos = new UserInfo(); 
     userInfos.setUser(person); 
     userInfos.setRoles(identity.getRoles()); 

     objectMapper.writeValue(response.getWriter(), userInfos); 
    } 
} 

、私は2つのサービス(PersonService & IdentityService)を実装しているshoul任意のデータベースへのアクセスを防止するためにモックとして使用することd次の

@Profile("test") 
@Service 
public class PersonServiceMock implements PersonService { 

    private static final Map<String, Person> USER_DB; 

    static { 
     Person valerian = new Student(); 
     valerian.setMail("[email protected]"); 

     USER_DB = new HashMap<>(); 
     USER_DB.put(valerian.getMail(), valerian); 
    } 

    @Override 
    public Person getPersonByMail(String mail) { 
     return USER_DB.get(mail); 
    } 

} 

- 最後に

@Profile("test") 
@Service 
public class IdentityServiceMock implements IdentityService { 

    private static final Map<String, Identity> USER_DB; 

    static { 
     Identity valerian = new Identity("[email protected]"); 

     USER_DB = new HashMap<>(); 
     USER_DB.put(valerian.getUsername(), valerian); 

     BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); 

     USER_DB.forEach((key, value) -> { 
      value.setEnabled(true); 
      value.setLocked(false); 
      value.setPassword(encoder.encode("pa$$w0rd")); 
     }); 
    } 

    @Override 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
     UserDetails ud = USER_DB.get(username); 
     return ud; 
    } 
} 

を、ここに私の「試験の開始は」私が書きましたが、それは望んでいるようなので、それは動作しません。

@ActiveProfiles("test") 
@RunWith(SpringRunner.class) 
@SpringBootTest 
@WebAppConfiguration 
public class AuthenticationTests { 

    @Autowired 
    private Filter filterChainProxy; 

    @Autowired 
    private WebApplicationContext context; 

    private MockMvc mockMvc; 

    @Before 
    public void before() { 
     mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filterChainProxy).build(); 
} 

    @Test 
    public void login() throws Exception { 

     ObjectMapper objectMapper = new ObjectMapper(); 
     LoginInfo loginInfo = new LoginInfo("[email protected]", "pa$$w0rd"); 

     MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/login") 
      .content(objectMapper.writeValueAsString(loginInfo)); 

     Person person = new Student("valerian", "none", "[email protected]"); 
     UserInfo expectedUserInfo = new UserInfo(person, null); 

     String expectedJSonContent = objectMapper.writeValueAsString(expectedUserInfo); 

     mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.status().isOk()) 
      .andExpect(MockMvcResultMatchers.content().json(expectedJSonContent)); 

    } 

} 

私は何か誤解しましたか?私を助けてくれますか?

答えて

1

OK。気にしないで。ちょうど私が模倣のようないくつかの考え方を誤解したのは、スタッビングを捏造することです。たとえモッキングとスタブがユニット/統合テストで明確にリンクされていたとしてもです。

さまざまなインターフェイスとサービスの「モック」実装を削除するように自分のコードを変更しました。このタイプのインプリメンテーションは、モックよりも擬似ビヘイビアの実装に似ています。最後に

、私は私のテストクラスのためにこれを持っている:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@WebAppConfiguration 
public class AuthenticationTests { 

    private static final String KNOWN_USER_MAIL = "[email protected]"; 
    private static final String KNOWN_USER_PASSWORD = "pa$$w0rd"; 

    private static Person KNOWN_STUDENT = new Student("valerian", "none", KNOWN_USER_MAIL); 
    private static Identity KNWON_IDENTITY = new Identity(KNOWN_USER_MAIL); 

    static { 
     BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); 

     KNWON_IDENTITY.setEnabled(true); 
     KNWON_IDENTITY.setLocked(false); 
     KNWON_IDENTITY.setPassword(encoder.encode(KNOWN_USER_PASSWORD)); 
    } 

    @Autowired 
    // Attribute name very important 
    private Filter springSecurityFilterChain; 

    @Autowired 
    private WebApplicationContext context; 

    @MockBean // IdentityService automatically mocked when used 
    private IdentityService identityService; 

    @MockBean // PersonService automatically mocked when used 
    private PersonService personService; 

    private MockMvc mockMvc; 

    @Before 
    public void before() { 

     mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilters(springSecurityFilterChain).build(); 

     // Stub to define the behaviour of the services when they are used 
     Mockito.when(identityService.loadUserByUsername(KNOWN_USER_MAIL)).thenReturn(KNWON_IDENTITY); 
     Mockito.when(personService.getPersonByMail(KNOWN_USER_MAIL)).thenReturn(KNOWN_STUDENT); 
    } 

    @Test 
    public void login_success() throws Exception { 

     ObjectMapper objectMapper = new ObjectMapper(); 
     LoginInfo loginInfo = new LoginInfo(KNOWN_USER_MAIL, KNOWN_USER_PASSWORD); 

     MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/login") 
       .content(objectMapper.writeValueAsString(loginInfo)); 

     UserInfo expectedUserInfo = new UserInfo(KNOWN_STUDENT, KNWON_IDENTITY.getRoles()); 

     String expectedJSonContent = objectMapper.writeValueAsString(expectedUserInfo); 
     mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.status().isOk()) 
       .andExpect(MockMvcResultMatchers.content().json(expectedJSonContent)); 

    } 

} 

私は注釈@MockBeanの魔法とスタブに感銘を受けています。 :)

関連する問題