
기본 기능들을 구현하고, Spring Security를 통해 인증/인가를 적용했을때 통합 테스트에서 어려움을 겪었다.
먼저, 내 테스트 전략은 이러했다.
인증에 대한 테스트는 별도로 수행한다. (custom filter/security filter의 동작 유무)
따라서 slice test나 domain integration test에는 인증이 간섭해서는 안된다.
이 목적을 달성하려면, 컨트롤러 단위 테스트와 통합 테스트 시 별도의 처리가 필요하다.
(service unit test는 시큐리티 설정의 영향을 받지 않음)
먼저, controller 단위 테스트는 간단하게 인증 과정을 배제할 수 있다.
controller 테스트 클래스에 @AutoConfigureMockMvc(addFilters = false) 를 추가해주면 된다.
@WebMvcTest(MatchController.class)
@AutoConfigureMockMvc(addFilters = false)
class MatchControllerTest {
Spring Text Context에서 MockMvc를 자동으로 설정하고 Bean으로 등록해준다.
MockMvc는 기본적으로 실제 애플리케이션처럼 모든 서블릿 필터(Servlet Filters)를 거쳐가도록 설계되어 있다. (Spring Security Filter Chain 포함)
하지만, addFilters=false가 filter chain을 무력화시키기 때문에, 인증 설정을 배제할수 있게 되고, 순수 컨트롤러 로직만 검증할 수 있다.
만일 보안 로직을 포함해서 테스트하고싶다면 @WithMockUser를 쓰면 된다.
게시글의 커서 기반 조회 테스트에서도 같은 문제가 발생했다. service-repository 흐름을 보는 domain test였는데, 통합 테스트는 JwtProvider, JwtFilter, SecurityConfig 등 인증 관련 Bean을 포함한 모든 빈을 로드하고 주입하기 때문에 여기서도 인증 설정을 배제해야했다.
방법1: SecurityConfig를 테스트 환경에서 아예 배제한다. (@Profile(”!test”))
방법2: property 값에 따라 on/off를 설정한다. (@ConditionalOnProperty)
@RequiredArgsConstructor
@Configuration
@ConditionalOnProperty(name = "ssup.security.enabled", havingValue = "true", matchIfMissing = true)
public class SecurityConfig {
matchIfMissing = true: 값이 없으면 기본값을 true로 설정한다.spring:
config:
activate:
on-profile: test
ssup:
security:
enabled: false
이렇게 설정하면, 인증 테스트(auth-test profile)와 운영 환경에서는 true로 작동해서 Security Context가 동작하고, 기본 테스트(test profile)는 Security Context를 배제하고 테스트의 목적에 집중할 수 있게 된다.
또한, 인증 로직을 테스트할때 oauth2와 같은 설정을 모두 포함해서 테스트하는 경우는 드물다. 이때, 그러한 Bean들을 모두 Mock 처리하면 가독성이 떨어질 수 있다. 이때는 TestSecurityConfig와 같은 테스트용 Security Config를 따로 만들어서 사용하면 된다.
이렇게 하면, 인증 테스트와 인증을 제외한 domain/unit/slice 테스트들은 별도의 profile에서 수행하게 된다.
따라서, CI 시에도 step을 2개로 나눠서 수행한다.
- name: Run tests (test profile)
working-directory: backend
env:
SPRING_PROFILES_ACTIVE: test
run: |
chmod +x ./gradlew
./gradlew test --tests "*" --tests "!*Auth*"
- name: Run tests (auth-test profile)
working-directory: backend
env:
SPRING_PROFILES_ACTIVE: auth-test
run: |
chmod +x ./gradlew
./gradlew test --tests "*Auth*"

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig' defined in file [/com/ssup/backend/global/config/SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 3: Error creating bean with name 'securityConfig': Requested bean is currently in creation:
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:795)
