0

특정 수의 컨트롤러가있는 스프링 부트 MVC 애플리케이션을 개발 중입니다. 내 루트 컨트롤러는 : 나는 성공적으로 컨트롤러 MVC 테스트를 구현 한스프링 부트 WebMvc 테스트에 스프링 보안을 포함하지 않음

@Controller 
@RequestMapping("/") 
public class RootController { 

    @GetMapping 
    public String showStartPage() { 
     log.info("GET: Show home page"); 
     return "index"; 
    } 
} 

. 내 RootController에 대한 시험은 다음과 같습니다

@RunWith(SpringRunner.class) 
@WebMvcTest(RootController.class) 
public class RootControllerMvcTest { 

    @Autowired 
    private MockMvc mvc; 

    @Test 
    public void testRoot() throws Exception { 
     mvc.perform(get("/").accept(MediaType.TEXT_HTML)) 
      .andExpect(status().isOk()) 
      .andExpect(view().name("index")); 
    } 
} 

문제 : 봄 보안 인증 및 권한 부여를 도입 할 때

그러나, 모든 MVC 컨트롤러 테스트 고장. 루트 컨트롤러 테스트에 대한 어설 션 오류는 다음과 같습니다

java.lang.AssertionError: Status 
Expected :200 
Actual :401 

내 보안 구성은 다음과 같습니다

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private UserDetailsService userDetailsService; 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
      .antMatchers("/", "/fonts/*").permitAll() 
      .antMatchers("/user/**").hasAuthority("ADMIN") 
      .anyRequest().fullyAuthenticated() 
      .and() 
      .formLogin() 
      .loginPage("/login") 
      .failureUrl("/login?error") 
      .usernameParameter("email") 
      .permitAll() 
      .and() 
      .logout() 
      .logoutUrl("/logout") 
      .deleteCookies("remember-me") 
      .logoutSuccessUrl("/") 
      .permitAll() 
      .and() 
      .rememberMe(); 
    } 

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

해결책

:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@AutoConfigureMockMvc 
public class RootControllerMvcTest { 
... 
} 
: 다음

, 내가 가진 문제를 해결하기 위해 관리

이 경우 내 테스트는 전체 응용 프로그램 컨텍스트를로드합니다.

내 질문은 :

  1. 어떻게이 컨트롤러의 인증 및 권한 부여 과정과 시험에만 논리에서 분리 내 MVC 테스트를 유지할 수 있습니까?
  2. 인증 및 권한 부여 구현을 테스트하는 가장 좋은 방법은 무엇입니까? 이 목적으로 @SpringBootTest를 사용해야합니까?
  3. 내 컨트롤러와 보안 논리를 별도로 테스트하는 것이 좋습니까?

고맙습니다.

+0

[테스트 스프링 부트 보안 간단하게] (http://stackoverflow.com/questions/31812054/testing-spring-boot-security-simply) –

+0

감사합니다. 유용한 링크입니다. 하지만 우선, MockMvc로 컨트롤러를 테스트 할 수 있는지 그리고 스프링 보안을 사용하지 않고 컨트롤러를 테스트 할 수 있는지를 알아 내려고합니다. –

답변

0

많은 의견이 있지만 내 두 센트를 제공 할 것입니다. 첫째, 목표는 적용 범위와 출시시기입니다. 즉, 구현하기에 합리적으로 빠른 솔루션이 필요하며 프로덕션 환경에서 작동하는 소프트웨어를 제작해야합니다. 그래서 나는 이데올로기에 대해 너무 걱정하지 않는다.

그래서 저는 단위 테스트와 통합 테스트를 혼합하여 사용하고 싶습니다. 단위 테스트가 100 %에 가까운 코드 커버리지를 달성하려고 시도하는 경우 통합은 다른 시스템과의 상호 작용에 더 중점을 둡니다. DB, 클라이언트, 기타 서비스 등. BTW에서는 단위 테스트와 통합 테스트가 모두 자동화되어야하므로 통합은 인간 존재없이 수행되어야합니다.

내 컨트롤러를 단위 테스트 할 때 과거에 사용한 두 가지 방법이 있습니다. 하나는 Spring 컨텍스트 외부에서 컨트롤러 메서드를 직접 호출하는 것입니다. 우리는 코드 커버리지 목표를 달성 할 수있었습니다. 이것은 잠깐 동안 일했지만 HATEOS가 기반으로하는 링크를 만들기 위해 Spring MVC 컨텍스트를 사용하는 것에 의존하는 Spring의 HATEOS 기능을 사용하기 시작했을 때 실패했습니다. 그래서 우리는 단위 테스트를 위해 MockMvc로 전환했습니다. 이것이 효과가 있었고 커버리지 목표를 달성했습니다. 이제 귀하의 경우에 문제는 보안이 당신의 단위 테스트의 방식으로 가고 있다는 것입니다. 보안 목표를 달성 할 수 있도록 보안 구성을 단계별로 살펴보고 통합 테스트에서 보안을 테스트 할 수 있습니다. 이는 SecurityConfig 클래스의 @Profile 특수 효과를 사용하여 수행 할 수 있습니다. 마이크로 서비스 네트워크에서는 @Profile을 사용하여 구성 클래스를 활성화 및 비활성화합니다.예를 들어 특정 프로파일이 사용되는 경우 Eureka 서버에만 등록합니다. 당신이 이것을 할 수있는 여러 가지 방법이 있습니다. 한 가지 방법은 유레카 구성을 위해 수행 한 작업을 수행하는 것입니다.이 구성은 우리가 active-eureka이라고하는 프로필이있는 경우에만 사용 가능합니다.이 이름을 사용했습니다. 이렇게하면 IDE에서 마이크로 서비스를 실행할 때 유레카 서버에 접속하는 것을 방지 할 수 있습니다. 귀하의 경우 activate-security이라는 프로필을 가질 수 있습니다. 이렇게하면 재미있는 일을 망칠 수있는 보안으로 MockMvc 기반의 단위 테스팅을 할 수 있습니다.

이제 단위 테스트를 수행하면서 보안 기능을 사용하는 서비스에 대한 통합 테스트를 수행해야합니다. 이 방법에는 여러 가지가 있습니다. 우리가 사용하는 접근법 중 하나는 @SpringBootTest 주석을 TestRestTemplate 클래스와 함께 사용하는 것입니다. 이것은 마이크로 서비스를 시작한 다음 TestRestTemplate을 사용하여 실제 서비스 호출을합니다. TestRestTemplate은 웹 서비스가 실행중인 포트를 알고 있다는 점을 제외하면 실제 http RestTemplate 클라이언트이므로 포트를 파악하기 위해 보일러 플레이트 코드를 제거 할 수 있습니다. TestRestTamplte을 사용하면 URL의 http://host:port 부분을 생략 할 수 있습니다. 그것은 here라고 기술되어있다. 우리가 보안 기능을 사용하도록 설정했다면, 우리가 실제 보안 클라이언트 인 것처럼 보안을 수행해야합니다. 즉, 보안을 강화하고 적극적으로 참여하지 말아야한다는 것을 의미합니다. 이는 단위 테스트 중 우리가 한 일.

단위 테스트와 통합 테스트의 목적은 다릅니다. 위에 요약 된 접근 방식을 사용하면 이러한 목표에 독립적으로 집중할 수 있습니다.

+0

답변 해 주셔서 감사합니다. 필자는 컨트롤러 테스트 로직을'@Profile'과 분리하는 데 성공했습니다. 그래도 약간 다르게 구현했습니다. 모범 사례 및 통합 테스트 조언이 정말 도움이됩니다! 내 통합 테스트를 구현하는 데 도움이 될 것입니다. –

0

대답 1 :

  1. 추가 src/test/java/resources/application-disabled-security.yml을 : 다음과 같이 내 MVC 테스트에서 봄 보안 기능을 제외한


    보안 : 기본 : 활성화 : 거짓

  2. mvc 테스트에 @ActiveProfiles("disabled-security") 주석을 추가했습니다. 이전에 제안 된

0

방법은 봄의 최신 버전에 deprecated 것으로 보인다.

다른 한편으로 동일한 기능을 추가 인수로 사용할 수 있습니다.

예를를 들어, WebMvcTest 내 경우에는 내가

@RunWith(SpringRunner.class) 
@WebMvcTest(value = ImportController.class, secure = false) 

@RunWith(SpringRunner.class) 
@WebMvcTest(ImportController.class) 

에서 이동하고는 모두 잘했다.

관련 문제