Intro

  • AOP는 IoC/DI, 서비스 추상화와 더불어 스프링의 3대 기술임.

단위 테스트

  • 작은 단위의 테스트가 더 좋음. → 테스트 실패시 원인을 찾기가 쉬움. 테스트 단위가 작아야 테스트의 의도나 내용이 분명해짐.
  • 테스트의 대상이 환경이나, 외부 서버, 다른 클래스의 코드에 종속되고 영향을 받지 않도록 고립시킬 필요가 있음. → 테스트 대역 사용
  • 통합테스트 - 두 개 이상의 성격이나 계층이 다른 오브젝트가 연동하도록 만들어 테스트하거나, 또는 외부의 DB나 파일, 서비스 등의 리소스가 참여하는 테스트
  • 단위테스트 vs. 통합 테스트
    • 항상 단위테스트를 먼저 고려함.
    • 외부 리소스 사용해야만 가능한 테스트는 통합 테스트로만든다.
    • 스프링 테스트 컨텍스트 프레임워크를 이용하는 테스트는 통합 테스트임.
  • 코드를 작성하면서 테스트는 어떻게 만들 수 있을까를 생각해보는 것은 좋은 습관임.

목 프레임워크

  • 단위 테스트를 만들기위해서는 스텁이나 목 오브젝트의 사용이 필수적임. → 단위 테스트를 만들 때 목 오브젝트를 만드는 것은 번거로운 일임. (테스트에서 사용하지 않는 인터페이스도 구현해야 함.)
  • Mockito 프레임워크
    • 목 오브젝트를 편리하게 작성하도록 도와주는 프레임워크임.
    • mock() 메소드 - org.mockito.Matchers 클래스의 스태틱 메소드
  • Mockito 사용 단계
    @Test
    public void mockUpgradeLevels() throws Exception {
    	UserServiceImpl userServiceImpl = new UserServiceImpl();
    	//1) 인터페이스를 이용해 목 오브젝트 생성
    	UserDao mockUserDao = mock(UserDao.class);
    	//2) 목 오브젝트가 리턴할 값이 있으면 지정
    	//mockUserDao.getAll()이 호출됐을 때, users 리스트 리턴
    	when(mockUserDao.getAll()).thenReturn(this.users);
    	//3) 테스트 대상 오브젝트에 DI해서 목 오브젝트가 테스트 중에 사용되도록 함.
    	userServiceImpl.setUserDao(mockUserDao);
    	...
    	//4) 테스트 대상 오브젝트를 사용한 후에 목 오브젝트의 특정 메소드가 호출됐는지, 어떤 값을 가지고 몇 번 호출됐는지를 검증한다.
    	//update() 메소드가 두 번 호출됐는지 확인
    	verify(mockUserDao, times(2)).update(any(User.class));
    	...
    }
    

다이내믹 프록시와 팩토리 빈

  • 프록시 - 클라이언트가 사용하려고 하는 실제 대상인 것처럼 위장해서 클라이언트의 요청을 받아주는 것
    • 프록시의 특징은 타깃과 같은 인터페이스 구현 & 프록시가 타깃을 제어할 수 있는 위치에 있음
    • 사용목적에 따른 구분
        1. 클라이언트가 타깃에 접근하는 방법 제어 → 프록시 패턴
        1. 타깃에 부가적인 기능 부여 → 데코레이터 패턴
  • 타깃(target) or 실체(real subject) - 프록시를 통해 최종적으로 요청을 위임받아 처리하는 실제 오브젝트

데코레이터 패턴

  • 타깃에 부가적인 기능을 런타임 시 다이내믹하게 부여해주기 위해 프록시를 사용하는 패턴임.
    • 다이내믹하게 기능을 부가한다? 컴파일시점, 즉 코드상에서는 어떤 방법과 순서로 프록시와 타깃이 연결되어 사용되는지 정해져있지 않음.
  • 데코레이터 패턴에서는 같은 인터페이스를 구현한 타겟과 여러 개의 프록시를 사용할 수 있음.
  • 프록시가 여러 개이므로 순서를 정해서 단계적으로 위임하는 구조로 만듦.
  • 타깃의 코드를 손대지 않고, 클라이언트가 호출하는 방법도 변경하지 않은 채로 새로운 기능을 추가할 때 유용한 방법임.

프록시 패턴

  • 프록시 패턴의 프록시는 타깃의 기능을 확장하거나 추가하지 않고, 클라이언트가 타깃에 접근하는 방식을 변경해줌.
  • 클라이언트로 하여금 원격 오브젝트에 대한 접근 방법을 제공함.
  • 특별한 상황에서 타깃에 대한 접근 권한을 제어하기 위해 사용함.
  • 구조적으로 보면 데코레이터와 유사하지만 프록시는 코드에서 자신이 만들거나 접근할 타깃 클래스 정보를 알고 있는 경우가 많음.

다이내믹 프록시

  • 다이내믹 프록시는 프록시 팩토리에 의해 런타임 시 다이내믹하게 만들어지는 오브젝트임.
    • 클라이언트는 다이내믹 프록시 오브젝트를 타깃 인터페이스를 통해 사용할 수 있음.
  • java.lang.reflect 패키지 - 프록시를 쉽게 만들도록 지원해주는 클래스들이 있음.
  • 프록시의 기능
    • 타깃과 같은 메소드를 구현하고 있다가 메소드가 호출되면 타깃 오브젝트로 위임
    • 지정된 요청에 대해서는 부가기능 수행
  • 프록시 만들기가 번거로운 이유
    • 타깃의 인터페이스를 구현하고 위임하는 코드를 작성하기 어려움. → JDK의 다이내믹 프록시로 해결
    • 부가기능 코드가 중복될 가능성이 있음.
  • 리플렉션 - 다이내믹 프록시는 리플렉션 기능을 이용해서 프록시를 만들어줌. 리플렉션은 자바의 코드 자체를 추상화해서 접근하도록 만든 것임.
    • java.lang.reflect.Method 인터페이스
      • 메소드에 대한 자세한 정보를 담고 있음.
      • 특정 오브젝트의 메소드 실행 가능 → invoke() 메소드, 메소드를 실행시킬 대상 오브젝트와 파라미터 목록을 받아서 메소드를 호출한 뒤에 그 결과를 Object 타입으로 돌려줌.

팩토리 빈

  • 팩토리 빈 - 스프링을 대신해서 오브젝트의 생성로직을 담당하도록 만들어진 특별한 빈임.

  • 스프링의 FactoryBean 인터페이스를 구현한 클래스를 스프링의 빈으로 등록하면 됨.

  • code(FactoryBean 인터페이스)

    package org.springframework.beans.factory;
    
    public interface FactoryBean<T> {
    	T getObject() throws Exception; // 빈 오브젝트 생성해서 돌려주기
    	Class<? extends T> getObjectType(); //생성되는 오브젝트 타입 알려주기
    	boolean isSingleton(); //getObject()가 돌려주는 오브젝트가 항상 같은 싱글톤 오브젝트인지 알려주기
    }
    
  • 프록시 팩토리 빈 방식의 장점 - 타깃 인터페이스를 구현하는 클래스를 일일이 만드는 번거로움을 제거할 수 있음.

    • DI가 중요한 역할을 함.
  • 프록시 팩토리 빈의 한계

    • 프록시를 통해 타깃에 부가기능을 제공하는 것은 메소드 단위로 일어나는 일임. 여러 개의 클래스에 공통적인 부가기능을 제공하는 일은 불가능함.
    • 하나의 타깃에 여러 개의 부가기능을 적용하는 것도 어려움.
    • DI를 적용해 해결할 수 있을까?

스프링의 프록시 팩토리 빈

ProxyFactoryBean

  • 프록시를 생성해서 빈 오브젝트로 등록하게 해주는 팩토리 빈임.
    • TxProxyFactoryBean과 달리, ProxyFactoryBean은 순수하게 프록시를 생성하는 작업만을 담당하고 프록시를 통해 제공해줄 부가기능은 별도의 빈에 둘 수 있음.
  • ProxyFactoryBean이 생성하는 프록시에서 사용할 부가기능은 MethodInterceptor 인터페이스를 구현해서 만든다.
    • MethodInterceptor의 invoke() 메소드는 ProxyFactoryBean으로부터 타깃 오브젝트에 대한 정보까지도 함께 제공받음.
    • 따라서 MethodInterceptor 오브젝트는 타깃이 다른 여러 프록시에서 함께 사용할 수 있고, 싱글톤 빈으로 등록 가능함.

ProxyFactoryBean의 특징

  1. MethodInvocation
  • 일종의 콜백 오브젝트임.
  • proceed() 메소드를 실행하면 타깃 오브젝트의 메소드를 내부적으로 실행해주는 기능이 있음.
  • ProxyFactoryBean은 작은 단위의 템플릿/콜백 구조를 응용해서 적용했기 때문에 템플릿 역할을 하는 MethodInvocation을 싱글톤으로 두고 공유할 수 있음.
  1. ProxyFactoryBean에 이 MethodInterceptor를 설정해 줄 때는 일반적인 DI 경우처럼 수정자 메소드를 사용하는 대신 **addAdvice()**라는 메소드를 사용함.
  • ProxyFactoryBean 하나로 여러 개의 부가 기능을 제공해주는 프록시 만들 수 있음.
  • advice - MethodInterceptor처럼 타깃 오브젝트에 적용하는 부가기능을 담은 오브젝트. 타깃 오브젝트에 종속되지 않는 순수한 부가기능을 담은 오브젝트임.
  1. 인터페이스 자동 검출 기능
  • JDK 다이내믹 프록시의 경우 Hello 인터페이스를 통해 다이내믹 프록시 오브젝트의 타입을 결정함.
  • 인터페이스를 알려주지 않아도 ProxyFactoryBean에 있는 인터페이스 자동검출 기능을 사용해 타깃 오브젝트가 구현하고 있는 인터페이스 정보를 알아냄.
  • 타깃 오브젝트가 구현하고 있는 모든 인터페이스를 동일하게 구현하는 프록시를 만들어주는 기능이 있음.

포인트 컷

  • 기존에 InvocationHandler를 직접 구현했을 때는 메소드의 이름을 가지고 부가기능을 적용할 대상 메소드를 선정하는 것이 있었음.
  • 스프링의 ProxyFactoryBean과 MethodInterceptor를 사용하는 방식에서도 메소드 선정 기능을 넣을 수 있을까?
    • 불가능함. 트랜잭션 적용 메소드 패턴은 프록시마다 다를 수 있기 때문에 여러 프록시가 공유하는 MethodInterceptor에 특정 프록시에만 적용되는 패턴을 넣으면 문제가 됨.
    • 어떻게 해결할까?
      • MethodInterceptor에는 재사용 가능한 순수한 부가기능 제공 코드만 남긴다. 대신 프록시에 부가기능 적용 메소드를 선택하는 기능을 넣음.
  • 스프링의 ProxyFactoryBean 방식은 **부가기능(advice)과 메소드 선정 알고리즘(pointcut)**을 활용하는 유연한 구조 제공.
    • advice - 부가기능을 제공하는 오브젝트
    • pointcut - 메소드 선정 알고리즘을 담은 오브젝트
    • 어드바이스와 포인트 컷은 모두 프록시에 DI로 주입돼서 사용됨.
  • 프록시로부터 어드바이스와 포인트컷을 독립시키고 DI를 사용하게 한 것은 전형적인 전략 패턴 구조임.
  • 어드바이저 = 포인트컷(메소드 선정 알고리즘) + 어드바이스(부가기능)

어드바이스와 포인트컷의 재사용

  • UserService 외에 새로운 비즈니스 로직을 담은 서비스 클래스가 만들어져도 이미 만들어둔 TransactionAdvice를 그대로 재사용할 수 있음.
  • 메소드의 선정을 위한 포인트 컷이 필요하면 이름 패턴만 지정해서 ProxyFactoryBean에 등록하면 됨.

스프링 AOP

  • 부가기능의 적용이 필요한 타깃 오브젝트마다 거의 비슷한 내용의 ProxyFactoryBean 빈 설정 정보를 추가해야 함. 중복을 제거할 방법은 없을까?

자동 프록시 생성 빈 후처리기

  • DefaultAdvisorAutoProxyCreator는 어드바이저를 이용한 자동 프록시 생성기임.
  • 자동 프록시 생성 빈 후처리기 - 스프링이 생성하는 빈 오브젝트의 일부를 프록시로 포장하고, 프록시를 빈으로 대신 등록 가능함.
  • 적용할 빈을 선정하는 로직이 추가된 포인트컷이 담긴 어드바이저를 등록하고 빈 후처리기를 사용하면 일일이 ProxyFactoryBean 빈을 등록하지 않아도 타깃 오브젝트에 자동으로 프록시가 적용되게 할 수 있음.
  • 빈 후처리기는 클래스와 메소드 선정 알고리즘을 모두 갖고 있는 포인트 컷이 필요함.

포인트컷 표현식

  • 세밀한 기준을 이용해 클래스나 메소드를 선정하게 하려면 어떻게 해야할까? → (AspectJ) 포인트컷 표현식 사용
  • 정규식이나 JSP의 EL과 비슷한 일종의 표현식 언어를 사용해서 포인트컷을 작성할 수 있도록 함.
  • AspectJExpressionPointcut 클래스를 사용 - 클래스와 메소드의 선정 알고리즘을 포인트 컷 표현식을 이용해 한 번에 지정할 수 있게 해줌.
  • execution() 포인트컷 지시자를 이용한 포인트컷 표현식 문법.
    execution([접근제한자 패턴] 타입패턴 [타입패턴.] 이름패턴 (타입패턴 | "..", ...)[throws 예외 패턴])
    (\* []괄호는 옵션이므로 생략가능함.)
    
    • [접근제한자 패턴] : public, private과 같은 접근제한자.
    • 타입 패턴 : 리턴 값의 타입 패턴
    • [타입패턴.] : 패키지와 클래스 이름에 대한 패턴
    • 이름패턴 : 메소드 이름 패턴
    • (타입패턴 | “..”, …) : 파라미터의 타입 패턴을 순서대로 넣음.

부가기능의 모듈화

  • 비즈니스 로직을 담은 UserService에 트랜잭션을 적용한 과정
      1. 트랜잭션 서비스 추상화 : 트랜잭션 경계설정 코드를 비즈니스 로직을 담은 코드에 넣음. → 트랜잭션 적용이라는 추상적인 작업 내용은 유지한 채로 구체적인 구현 방법을 자유롭게 바꿀 수 있도록 서비스 추상화 기법 적용
      1. 프록시와 데코레이터 패턴 : 트랜잭션이라는 부가적인 기능을 어디에 적용할 것인가는 코드에 노출되어 있음. → DI를 이용해 데코레이터 패턴 적용. 트랜잭션을 처리하는 코드는 일종의 데코레이터에 담겨, 클라이언트와 비즈니스 로직을 담은 타깃 클래스 사이에 존재하도록 만들었음.
      1. 다이내믹 프록시와 프록시 팩토리 빈 : 비즈니스 로직 인터페이스의 모든 메소드마다 트랜잭션 기능을 부여하는 코드를 넣어 프록시 클래스를 만드는 작업은 오히려 큰 짐임. → JDK 다이내믹 프록시와 같은 프록시 기술을 추상화한 스프링의 프록시 팩토리 빈을 이용해서 다이내믹 프록시 생성방법에 DI 도입.
      1. 자동 프록시 생성 방법과 포인트컷 : 트랜잭션 적용 대상이 되는 빈마다 일일이 프록시 팩토리 빈을 설정해야 함. → 빈 생성 후처리 기법 활용. 프록시를 적용할 대상을 일일이 지정하지 않도록, 클래스를 선정하는 기능을 담은 확장된 포인트컷 사용함.
  • 부가기능의 모듈화
    • 트랜잭션 같은 부가기능은 핵심기능과 같은 방식으로 모듈화하기 힘들다. 부가기능이기 때문에 독립적인 방식으로 존재해서는 적용되기 어려움.
    • 어떻게 부가기능을 독립적인 모듈로 만들 수 있을까?
      • DI, 데코레이터 패턴, 다이내믹 프록시, 오브젝트 생성 후처리, 자동 프록시 생성, 포인트컷과 같은 기법은 이 문제를 해결하기 위한 방법.

AOP

  • 애스펙트(aspect): 애플리케이션의 핵심기능을 담고 있지는 않지만, 애플리케이션을 구성하는 중요한 한 가지 요소이고, 핵심기능에 부가되어 의미를 갖는 특별한 모듈임.
    • 어드바이스: 부가될 기능을 정의
    • 포인트컷 : 어디바이스를 어디에 적용할지 결정
  • Aspect Oriented Programming: 애플리케이션의 핵심적인 기능에서 부가적인 기능을 분리해서 애스펙트라는 독특한 모듈로 만들어서 설계하고 개발하는 방법임.
    • 애플리케이션을 다양한 측면에서 독립적으로 모델링하고, 설계하고, 개발할 수 있도록 만들어주는 것임. → 관점 지향 프로그래밍이라고도 함.
    • OOP를 돕는 보조적인 기술임.
  • 프록시를 이용한 AOP
    • 독립적으로 개발한 부가기능 모듈을 다양한 타깃 오브젝트의 메소드에 다이내믹하게 적용해주기 위해 가장 중요한 역할을 맡고있는 것이 프록시임.
    • 스프링은 프록시 방식의 AOP라고 할 수 있음.
  • AspectJ를 이용한 AOP
    • 타깃 오브젝트를 뜯어고쳐서 부가기능을 직접 넣어주는 직접적인 방법을 사용함.
    • 컴파일된 타깃의 클래스 파일 자체를 수정하거나 바이트코드를 조작함.
  • 용어
    • 타깃 : 부가기능을 부여할 대상임.
    • 어드바이스 : 타깃에게 제공할 부가기능을 담은 모듈임.
    • 조인 포인트 : 어드바이스가 적용될 수 있는 위치를 말함.
    • 포인트컷 : 어드바이스를 적용할 조인 포인트를 선별하는 작업 또는 그 기능을 정의한 모듈임.
    • 프록시 : 클라이언트와 타깃 사이에 투명하게 존재하면서 부가기능을 제공하는 오브젝트임.
    • 어드바이저 : 어떤 부가기능(어드바이스)을 어디에(포인트컷) 전달할 것인가를 알고있는 AOP의 기본 모듈임.
    • 애스펙트 : 한개 또는 그 이상의 포인트컷과 어드바이스의 조합으로 만들어짐.

AOP 네임스페이스

  • 스프링의 프록시 방식 AOP를 적용하려면 네 가지 빈을 등록해야함.
    • 자동 프록시 생성기 - DefaultAdvisorAutoProxyCreator 클래스를 빈으로 등록함.
    • 어드바이스 - 부가기능을 구현한 클래스를 빈으로 등록함.
    • 포인트컷 - AspectJExpressionPointcut을 빈으로 등록함.
    • 어드바이저 - DefaultPointcutAdvisor 클래스를 빈으로 등록함.
  • aop 스키마를 이용해 기계적으로 적용하는 빈들을 간편한 방법으로 등록함.
    • <aop: config>, <aop: pointcut>, aop:advisor 세가지 태그 정의.

트랜잭션 속성

  • 트랜잭션의 경계 안에서 진행된 작업은 commit() or rollback()만 가능함.
  • TransactionDefinition 타입 오브젝트를 사용하면 다음의 네 가지 속성을 이용해 트랜잭션의 동작방식을 제어할 수 있음.

1) 트랜잭션 전파(transaction propagation)

  • 트랜잭션의 경계에서 이미 진행 중인 트랜잭션이 있을 때 또는 없을 때 어떻게 동작할 것인가를 결정하는 방식
  • 트랜잭션 전파 속성
    • PROPAGATION_REQUIRED - 진행 중인 트랜잭션이 없으면 새로 시작, 이미 시작된 트랜잭션이 있으면 참여
    • PROPAGATION_REQUIRES_NEW - 항상 새로운 트랜잭션 시작
    • PROPAGATION_NOT_SUPPORTED - 트랜잭션 없이 동작하도록 만든다. 진행 중인 트랜잭션이 있어도 무시함.

2) 격리수준(isolation level)

  • 모든 DB 트랜잭션은 격리수준을 갖고 있어야함.
  • 적절하게 격리수준을 조정해서 가능한 한 많은 트랜잭션을 동시에 진행시키면서도 문제가 발생하지 않게 하는 제어가 필요함.

3) 제한시간

  • 트랜잭션을 수행하는 제한시간을 설정할 수 있음.

4) 읽기전용

  • 읽기전용으로 설정해두면 트랜잭션 내에서 데이터를 조작하는 시도를 막아줄 수 있음.

트랜잭션 인터셉터와 트랜잭션 속성

  • 메소드별로 다른 트랜잭션 정의를 적용하려면 어드바이스의 기능을 확장해야함.
  • TransactionInterceptor - 스프링이 제공하는 트랜잭션 경계설정 어드바이스
    • 런타임 예외가 발생하면 트랜잭션은 롤백
    • 체크 예외 발생의 경우 트랜잭션은 커밋
    • rollbackOn() 속성 - 특정 체크 예외의 경우는 트랜잭션 롤백, 특정 런타임 예외에 대해서는 트랜잭션 커밋
    • Properties 타입의 transactionAttributes 프로퍼티 - 트랜잭션 속성을 정의한 프로퍼티
      • 메소드 패턴과 트랜잭션 속성을 키와 값으로 갖는 컬렉션임.

포인트컷과 트랜잭션 속성의 적용 전략

1) 트랜잭션 포인트컷 표현식은 타입 패턴이나 빈 이름을 이용

  • (쓰기 작업이 없는) 단순 조회 메소드 → 모두 트랜잭션 적용
  • 조회 메소드→ 읽기전용으로 트랜잭션 속성 설정
  • 복잡한 조회 메소드 → 제한시간 지정
  • 트랜잭션의 경계로 삼을 클래스들 정해지면, 그 클래스들이 모여 있는 패키지를 전부 선택하거나 클래스 이름에서 일정한 패턴을 찾아 표현식으로 만든다.
  • 가능하면 클래스보다는 인터페이스 타입을 기준으로 타입 패턴 적용.

2) 공통된 메소드 이름 규칙을 통해 최소한의 트랜잭션 어드바이스와 속성을 정의한다.

  • 기준이 되는 몇 가지 트랜잭션 속성을 정의하고 그에 따라 적절한 메소드 명명 규칙을 만들어두면 하나의 어드바이스만으로 애플리케이션의 모든 서비스 빈에 트랜잭션 속성을 지정할 수 있음.
    • 예를 들어 조회의 경우 - get or find를 메소드 명의 접두사로 사용

3) 프록시 방식 AOP는 같은 타깃 오브젝트 내의 메소드를 호출할 때는 적용되지 않는다.

  • 타깃 안에서의 호출에는 프록시가 적용되지 않는 문제
    • 해결1) 스프링 API를 이용해 프록시 오브젝트에 대한 레퍼런스를 가져온 뒤에 같은 오브젝트의 메소드 호출도 프록시를 이용하도록 강제
    • 해결2) AspectJ와 같은 타깃의 바이트코드를 직접 조작하는 방식의 AOP 기술 적용

애노테이션 트랜잭션 속성과 포인트컷

  • 세밀한 트랜잭션 속성의 제어가 필요한 경우 → 설정파일에서 패턴으로 분류 가능한 그룹을 만들어서 일괄적으로 속성을 부여하는 대신에 직접 타깃에 트랜잭션 속성정보를 가진 애노테이션을 지정

트랜잭션 애노테이션

  • @Transactional
    • 이 애노테이션의 타깃은 메소드와 타입임. → 메소드, 클래스, 인터페이스에 사용가능함.
    • 트랜잭션의 속성을 정의하고, 동시에 포인트컷의 자동 등록에도 사용됨.
    • 메소드마다 @Transactional을 부여하고 속성을 지정할 수 있음.
    • 문제) 코드가 지저분해지고, 동일한 속성 정보를 가진 애노테이션을 반복 사용함. → 스프링은 @Transactional을 적용할 때 4단계의 대체 정책을 이용하게 해줌. 메소드의 속성을 확인할 때 타깃 메소드, 타깃 클래스, 선언 메소드, 선언 타입의 순서에 따라서 애노테이션이 적용됐는지 확인하고, 가장 먼저 발견되는 속성정보를 사용하게 함.

트랜잭션 지원 테스트

선언적 트랜잭션과 트랜잭션 전파 속성

  • 선언적 트랜잭션(Declarative transaction) - AOP를 이용해 코드 외부에서 트랜잭션의 기능을 부여해주고 속성을 지정할 수 있게 하는 방법
  • 프로그램에 의한 트랜잭션(Programmatic transaction) - TransactionTemplate이나 개별 데이터 기술의 트랜잭션 API를 사용해 직접 코드 안에 사용하는 방법

트랜잭션 동기화와 테스트

  • 스프링의 트랜잭션 추상화가 제공하는 트랜잭션 동기화 기술과 트랜잭션 전파 속성 덕분에 테스트도 트랜잭션으로 묶을 수 있음.
  • 테스트에서 트랜잭션을 시작하거나 조작할 수 있는 기능은 유용함.
  • 롤백 테스트 - 테스트 내의 모든 DB 작업을 하나의 트랜잭션 안에서 동작하게하고 테스트가 끝나면 무조건 롤백하는 테스트

테스트를 이용한 트랜잭션 애노테이션

  • @Transactional
    • 적용하면 테스트 메소드에 트랜잭션 경계가 자동 설정됨.
    • 테스트가 끝나면 자동 롤백
  • @Rollback
    • 테스트 메소드 안에서 진행되는 작업을 하나의 트랜잭션으로 묶고 싶지만 강제 롤백을 원하지 않는 경우 이용함.
    • 롤백 여부를 지정하는 값을 갖고 있으며, 기본 값은 @Rollback(true)임.
  • @TransactionalConfiguration
    • 테스트 클래스의 모든 메소드에 트랜잭션을 적용하면서 모든 트랜잭션이 롤백되지 않고 커밋되게 할 경우 사용함.
    • 클래스 레벨에 부여할 수 있는 애노테이션임. 롤백에 대한 공통 속성을 지정할 수 있음.

효과적인 DB 테스트

  • 단위 테스트와 통합테스트는 클래스를 구분해서 만드는 것이 좋음.

참고 자료