본문 바로가기
Programming

[F-Lab 챌린지 30일차 TIL] 스프링 시큐리티 테스트, 토비 스프링 공부

by 구튼탁 2023. 7. 27.
728x90

알고리즘

재귀 정의하기

  1. 점화식에 대한 정의, 즉 상태 정의 필요함. 중간에 다른 작업으로 변경할 수 없으므로 인자의 값을 바꾸는 것만으로 문제를 풀 수 있는 함수를 만들어야 한다.
  2. 종료 조건을 제대로 작성해야 한다. 종료 조건이란 원하는 순간에 재귀 호출을 멈추고 값을 반환하도록 만드는 것
  3. 작업의 시작과 끝을 정의했으면 점화식을 세운다

문제


프로젝트

Integration Testing

Context Management : 테스트 환경에서 어플리케이션 컨텍스트를 관리하는 것

  • @ContextConfiguration: 테스트 클래스에 대한 어플리케이션 컨텍스트 구성 정보를 지정한다.
    • Component 클래스로 구성 정보 설정하기component class 에 해당하는 것
      • @Configuation 선언된 클래스
      • A component (that is, a class annotated with @Component, @Service, @Repository, or other stereotype annotations).
      • Any class that contains @Bean-methods.
      • Any other class that is intended to be registered as a Spring


@ExtendWith(SpringExtension.class) 
// ApplicationContext will be loaded from AppConfig and TestConfig 
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class}) 
class MyTest { 
	// class body... 
}

 

Integration Testing 도전

Integration Testing란 시스템의 각 구성요소가 잘 작동하는지 테스트 하는 것이다.

스프링 시큐리티 인증로직을 개발한 뒤 로그인 기능 통합 테스트가 필요했다. 로그인 기능에는 크게 LoginAuthenticationProvider, JsonAuthenticationFilter, SecurityFilterChain, MemberService 총 4가지 구성 요소가 있다.

 

문제 상황 1.

이 구성요소중 문제는 인증을 위해 멤버 정보를 조회하는 Service 가 DB 라는 외부 상태에 의존하는 상태여서 테스트를 수행할 수 없었다.

이렇게 외부 상태에 영향을 받는 경우에는 대역이란 것을 사용하면 된다. 외부요인을 대신하는 객체를 만들어 테스트에서 사용하는 것이다.

MemberService 를 대체하는 StubMemberService 를 만들었다.

대역의 종류에는 Stub, Fake, Spy, Mock 있다ㅏ. Mock이랑 Stub 이랑 좀 헷갈리는데 내가 만든 대역이
Stub 이 맞는지 다시 확인이 필요하다.

Stub : 구현을 단순한 것으로 대체한다. 테스트에 맞게 단순히 원하는 동작을 수행한다.
Mock : 기대한 대로 상호작용하는지 행위를 검증한다. 기대한 대로 동작하지 않으면 익셉션을 발생할 수 있다.

class StubMemberService extends MemberService {

    Map<String, Member> mockMembers;
    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    public StubMemberService() {
        super(new BCryptPasswordEncoder(), null);
        mockMembers = createMockMember();
    }

    @Override
    public void signup(MemberRequestDto memberRequestDto) {
        return;
    }

    @Override
    public Optional<Member> findMember(String id) {
        if (StringUtils.isBlank(id)) {
            return Optional.empty();
        }
        return Optional.ofNullable(mockMembers.get(id));
    }

    private Map<String, Member> createMockMember() {
        Map<String, Member> mockMembers = new HashMap<>();

        mockMembers.put("okUser", Member.builder()
                                        .id("okUser")
                                        .password(passwordEncoder.encode("123"))
                                        .build());
        mockMembers.put("failUser", Member.builder()
                                        .id("failUser")
                                        .password("123")
                                        .build());
        return mockMembers;
    }

}

문제 상황2.

MemberService 대신 StubMemberService 을 Bean 으로 등록해야 LoginAuthenticationProvider 에서 대역 객체로 멤버 정보 조회를 수행한다.

 

 

첫 번째 시도는 어플리케이션 컨텍스트에 빈을 주입하기 위해 @ContextConfiguration 부터 사용했다. 이 어노테이션 속성으로 어플리케이션 컨텍스트 구성 정보를 지정할 수 있다. 

속성으로 클래스를 지정했더니 지정한 클래스만 빈으로 등록이 되어버렸다.

로그인 기능에 관련된 모든 빈에 대한 정보를 알려줘야 하는 것 같다.

 

두 번째로는 @TestConfiguration 을 사용했다.

@TestConfiguration 을 사용하면 테스트 클래스에서 사용할 빈 정보를 등록할 수 있으며 어플리케이션 컨텍스트의 빈을 오버라이딩할 수 있다.테스트 클래스 내부에서 inner class 를 선언하거나 클래스를 따로 뺄거면 테스트 클래스에서는 @Import(class) 주석을 선언하면 된다.

 

`@TestConfiguration` 를 선언한 설정 클래스에 `StubMemberService` 를 `Bean` 으로 등록했는데, 이미 `MemberService` 이 빈으로 등록되어있다는 에러가 발생했다. 빈 오버라이딩이 되지 않은 것이다.

그래서 시도한 방법은 `@SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")` 을 선언했다. 

 

일단 테스트가 잘 동작하긴 했지만 빈을 오버라이딩을 못한 이유를 찾아봐야겠다

 

 

DB 구축하기 : AWS RDS

  • 프리티어 12개월 무료
  • 인스턴스 1개만 무료 사용
  • 월별 750시간 무료
  • 범용(SSD) 데이터베이스 스토리지 20GB 제한
  • db.t2.mirco 타입만 사용 가능
  • 백업 DB 및 스냅샷용 스토리지 20GB
  • RDS 생성할때 오토 백업 끄기
  • RDS 스토리지 자동 조정 끄기
  • Multi-AZProvisioned IOPS Storate 끄기

토비의 스프링

관심사의 분리

같은 관심사 끼리는 하나의 객체 안으로 또는 친한 객체로 모이게 하고, 관심이 다른 것끼리는 서로 영향을 주지 않도록 최대한 분리 하는 것이다.

IoC, 제어의 역전

제어 흐름 구조

코드의 흐름 제어를 제 3자에게 위임하는 것이다.

어떤 객체를 사용하는 쪽에서 객체를 직접 생성하고 관계를 맺고 어떤 기능 수행을 요청한다면 사용하는 쪽에서 흐름을 제어하는 것이다.

제어의 역전은 이 흐름을 제 3자가 대신해주고 객체는 외부에서 주입해준 참조값으로 객체를 사용한다.

Bean Factory, Spring Context, IoC 컨테이너

스프링에서 IoC 개념이 적용된 컴포넌트들이 있다.

  • Bean factory : 빈의 생성과 관계 설정 같은 제어를 담당하는 IoC 오브젝트다.
  • Spring Context : 별도의 설정 정보를 참고해서 빈의 생성, 관계설정 등의 제어 작업을 총괄한다.

스프링 IoC 용어 정리

  • bean : 스프링이 직접 생성과 제어를 담당하는 오브젝트
  • 빈 팩토리 : 스프링의 IoC 를 담당하는 핵심 컨테이너
  • 어플리케이션 컨텍스트 : 빈의 생성과 제어 + 스프링이 제공하는 애플리케이션 지원 기능
  • 설정정보 : IoC를 적용하기 위해 사용하는 메타정보
  • 컨테이너 or IoC 컨테이너 : IoC 방식으로 빈을 관리한다는 의미에서 애플리케이션 컨텍스트 또는 IoC 컨테이너라고도 한다.

싱글톤 레지스트리

  • 어플리케이션 컨텍스트의 또다른 역할을 뜻한다.
  • 싱글톤 패턴의 단점을 보완해서 싱글톤을 만들고 관리한다.
  • 빈은 기본적으로 싱글톤이기 때문에 stateless 하게 설계해야된다.

의존 관계란

  • 클래스 사이의 의존 관계 : 컴파일 타임에 구체 클래스와 의존 관계가 맺어지는 경우
  • 런타임에 결정되는 의존 관계 : 컴파일 타임에는 어떤 구체 클래스와 의존 관계가 맺어지는지 알 수 없고 런타임시에 결정되는 의존 관계다.

의존관계 주입이란 / DI, IoC/DI

런타임

  • 스프링은 IoC 를 의존관계 주입이라는 방식으로 구현했다.
  • 의존 관계 주입이란 구체적인 의존 오브젝트와 그것을 사용할 주체 오브젝트를 런타임 시에 연결해주는 작업을 말한다.
  • 런타임 시에 의존관계 주입은 제3자가 해주는데 이 역할을 IoC/DI 컨테이너가 한다.

의존관계 검색/주입

  • Dependency LookUp : 스스로 컨테이너에게 요청
  • Dependency Injection

 

728x90

댓글