2016-10-16 3 views
2

스프링 부트로 스프링 보안으로 구현 된 인증 필터를 테스트하기 위해 통합 테스트를 구현하고 싶습니다. 하지만 ... 난 ... 분실하고스프링 부트로 인증 필터 통합 테스트

첫째, 여기 내 "생산"구현 :

@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); 
    } 
} 

, 나는 두 가지 서비스 (PersonService & IdentityService)를 구현하는 말아야 데이터베이스 액세스를 방지하기 위해 모의로 사용할 수 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

확인. 신경 쓰지 마. 그것은 조롱과 스터 빙이 유닛/통합 테스트에서 명확하게 연결되어 있더라도 조롱과 같은 일부 개념을 오해 한 것입니다. & 스터 빙입니다.

다른 인터페이스와 서비스 모의 구현을 제거하기 위해 코드를 수정했습니다. 이러한 유형의 구현은 조롱 (mocking)보다 "가짜 - 행동"구현에 가깝습니다. 결국

, 내 테스트 클래스이 있습니다

@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과 스텁의 마법에 의해 감동. :)

관련 문제