TDD/JUnit5

SpringBoot test - @SpringBootTest, @TestConfiguration

wooweee 2023. 9. 23. 15:12
728x90

1. test 목적

  • @transactional test를 할 때, spring container를 이용한 proxy 객체 생성을 해야해서 일반 java 단위 test로 검사가 불가하다.
  • 때문에 test code 내부에 bean 등록과 spring container 환경, DI 를 이용해서 test 수행

 

package hello.jdbc.service;

import static hello.jdbc.connection.ConnectionConst.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

@Slf4j
@SpringBootTest // spring이 springContainer를 띄운다. - @Transactional 사용시, proxy에서 @bean을 사용하기 때문
class MemberServiceV3_3Test {

    @Autowired
    private MemberRepositoryV3 memberRepository;
    @Autowired
    private MemberServiceV3_3 memberService;

    // 이전 의존관계 주입을 하려는 memberRepository, memberService를 bean으로 등록해야 DI 가 가능해짐
    @TestConfiguration // testCode 내부에서 bean 등록하는 방법
    static class TestConfig{
        @Bean
        DataSource dataSource() { return new DriverManagerDataSource(URL,USERNAME,PASSWORD); }
        // transactionManger는 proxy(@Transactional)로부터 내부적으로 사용해야하기 때문에 bean 등록
        @Bean
        PlatformTransactionManager transactionManager(){
            return new DataSourceTransactionManager(dataSource());
        }
        @Bean
        MemberRepositoryV3 memberRepositoryV3() {
            return new MemberRepositoryV3(dataSource());
        }
        @Bean
        MemberServiceV3_3 memberServiceV3_3() {
            return new MemberServiceV3_3(memberRepositoryV3());
        }
    }

    /* *
    @BeforeEach
    void before(){
        // 설정으로 관리한 것
        DriverManagerDataSource dataSource = new DriverManagerDataSource(URL, USERNAME, PASSWORD);
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
        memberRepository = new MemberRepositoryV3(dataSource);
         memberService = new MemberServiceV3_3(memberRepository); // transaction 사용 위해서 dataSource 넘김
    }
    */

    @AfterEach
    void after() throws SQLException {
        memberRepository.delete("memberA");
        memberRepository.delete("memberB");
        memberRepository.delete("ex");
    }

    @Test
    void accountTransfer() throws SQLException {
        //given
        Member memberA = new Member("memberA", 10000);
        Member memberB = new Member("memberB", 10000);
        memberRepository.save(memberA);
        memberRepository.save(memberB);

        //when
        memberService.accountTransfer(memberA.getMemberId(), memberB.getMemberId(), 2000);

        //then
        Member findMemberA = memberRepository.findById(memberA.getMemberId());
        Member findMemberB = memberRepository.findById(memberB.getMemberId());
        assertThat(findMemberA.getMoney()).isEqualTo(8000);
        assertThat(findMemberB.getMoney()).isEqualTo(12000);
    }

    @Test
    void accountTransferEx() throws SQLException {
        //given
        Member memberA = new Member("memberA", 10000);
        Member memberEx = new Member("ex", 10000);
        memberRepository.save(memberA);
        memberRepository.save(memberEx);

        //when
        // accountTransfer으 실제 내부적의 business logic인 bizLogic()에서 params를 4개를 받지만
        // accountTransfer은 3개의 params만 받으면 된다.
        assertThatThrownBy(()->memberService.accountTransfer(memberA.getMemberId(), memberEx.getMemberId(), 2000))
                .isInstanceOf(IllegalStateException.class);


        //then
        Member findMemberA = memberRepository.findById(memberA.getMemberId());
        Member findMemberEx = memberRepository.findById(memberEx.getMemberId());
        assertThat(findMemberA.getMoney()).isEqualTo(10000);
        assertThat(findMemberEx.getMoney()).isEqualTo(10000);
    }

    // proxy 적용 확인 test
    @Test
    void AopCheck() {
        log.info("memberService class={}", memberService.getClass());
        log.info("memberRepository class={}", memberRepository.getClass());
        Assertions.assertThat(AopUtils.isAopProxy(memberService)).isTrue();
        Assertions.assertThat(AopUtils.isAopProxy(memberRepository)).isFalse();

    }
}

 

  • @SpringBootTest : springboot 환경 설정 - springboot가 제공하는 기본 @bean은 자동 등록
     
  • @TestConfiguration: test 환경 내부에서 사용자 @Bean 등록방법

 

참고 발행글 : 2023.09.23 - [spring/spring db1] - 4. 스프링과 문제해결 - 트랜잭션