[SpringBoot] 7. 서비스와 테스트, 트랜잭션

HJ·2022년 6월 29일
0

스프링부트, 입문!

목록 보기
7/10

홍팍 님의 스프링 부트, 입문! 강의를 보고 작성한 내용이며 이미지 또한 강의에 나오는 이미지를 따라 만들었습니다.
https://www.youtube.com/watch?v=Ym7cAtE2jQs&list=PLyebPLlVYXCiYdYaWRKgCqvnCFrLEANXt&index=29


20. 서비스 계층과 트랜잭션

20-1. 개념

  • Service : 처리 업무의 순서를 총괄

  • 업무 처리는 transaction 단위로 수행

  • 기존에 Controller가 Repository와 연동해서 수행하던 작업을 담당


20-2. 동작 흐름

  • Controller : 클라이언트로부터 요청을 전달받아서 Service에게 전달

  • Service : 전달받아서 정해진 작업 순서에 따라 작업 수행, 트랜잭션 관리

  • Repository : DB와 연동하여 작업을 수행 (Service내에 Repository 객체 존재)


20-3. 트랜잭션과 롤백

  • Transaction

    • 모두 성공되어야 하는 일련의 과정을 의미

    • transaction은 service가 관리

    • @Transactional : 해당 메소드를 트랜잭션으로 묶는다, 수행 중에 실패하면 해당 메소드가 수행되기 이전 상태로 rollback

  • Rollback : 중간에 하나의 과정이 실패한다면 진행 초기단계로 돌아감

20-4. Service 사용하기

  • 기본패키지/service 내에 클래스 생성

  • @Service : 해당 클래스를 서비스로 인식하여 스프링 부트에 객체를 생성(등록)

  • Repository를 통해 DB와 연동을 위해 클래스 내에 Repository 객체 생성

  • Controller에서 service 객체 생성 시 @Autowired 사용

  • 기존 코드 수정사항

    • 이전에 입력된 return 문을 service의 메소드를 호출하도록 변경

    • return 문에서 수행하던 일을 service의 메소드에서 수행되도록 작성


20-5. 참고

  • stream : 자바의 컬렉션이나 배열의 원소에 대한 작업 수행 시, for 문이 아닌 stream을 이용하여 람다함수형식으로 작성 가능

  • map : 항목들을 함수 결과에 해당하는 값으로 매핑

  • collect : stream 데이터를 원하는 자료형으로 변경


20-6. 테스트 코드

20-6-1. Controller

<ArticleApiController>

    // 트랜잭션 테스트
    // 트랜잭션 -> 실패 -> rollback
    @PostMapping("/api/transaction-test")
    public ResponseEntity<List<Article>> transactionTest(@RequestBody List<ArticleForm> dtos) {

        List<Article> createdList= articleService.createArticles(dtos);

        return (createdList != null) ?
                ResponseEntity.status(HttpStatus.OK).body(createdList) :
                ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
    }

20-6-2. Service

<ArticleService>

    // 트랜잭션 테스트
    @Transactional  // 해당 메소드를 트랜잭션으로 묶는다
    public List<Article> createArticles(List<ArticleForm> dtos) {
        
        // dto 묶음을 entity 묶음으로 변환
        // dtos의 항목들을 하나씩 Entity로 변환
        List<Article> articleList = dtos.stream().map(dto -> dto.toEntity()).collect(Collectors.toList());
        
        // entity 묶음을 DB에 저장
        // articleList를 반복하면서 하나씩 저장
        articleList.stream().forEach(article -> articleRepository.save(article));
        
        // 강제 예외 발생
        articleRepository.findById(-1L).orElseThrow(() -> new IllegalArgumentException("결재 실패!"));
        
        // 결과값 반환
        return articleList;
    }



21. 테스트 작성하기

21-1. Test 란?

  • 프로그램의 품질 검증을 위한 것

  • 원하는대로 프로그램이 동작하는지 확인하는 것

  • 예상 시나리오 작성, 실제 코드 결과와 비교하여 검증

    • 테스트 통과 시, refactoring

    • 실패 시, debuging

    • 성공하는 경우와 실패하는 경우에 대해서도 여러 케이스가 존재

  • TDD : Test Driven Development

  • @SpringBootTest : 스프링부트와 연동한 통합 테스트 수행 (해당 클래스는 스프링부트와 연동되어 테스팅된다 )

  • @Test : 해당 메소드가 test를 위한 코드임을 선언


21-2. service 검증 수행

  • Test 수행 메소드 우클릭 -> Generate -> Test

    • test 패키지 내부에서 원래 코드의 위치와 동일하게 생성됨
  • service에 대해 test를 진행하려고 하니까 service 객체를 Autowired를 통해 생성

  • 예상 코드 / 실제 코드 / 비교 코드로 메소드를 작성한다

    • 실제코드 : 직접 함수를 호출

    • 비교코드 : 결과(반환값)이 동일한지 비교

      • assertEquals(기댓값, 실제값)
  • 테스트에 @Transactional 추가

    • 테스트 종료 후 변경된 데이터를 롤백 처리

    • 데이터가 생성, 변경, 삭제되는 경우, 이와 같은 처리를 해야 전체 테스트가 성공적으로 수행됨

    • 테스트 코드의 경우, 테스트 성공 후 롤백됨

0개의 댓글