[Spring] 리포지토리 객체 테스트

WOOK JONG KIM·2022년 10월 31일
0
post-thumbnail
post-custom-banner

리포지토리 테스트

리포지토리는 개발자가 구현하는 레이어 중 가장 DB와 가까움

또한 JpaRepository를 상속받아 기본적인 쿼리 메서드 사용 가능

-> 구현하는 목적에 대해 특별히 고민하고 작성하자

우선 findById(), save()와 같은 기본 메서드에 대한 테스트는 별 의미 없음
-> 이미 검증을 마치고 제공되는 것

DB 연동 여부는 테스트 시 고려해볼 사항

DB는 굳이 따지면 외우 요인인데 만약 단위 테스트를 고려한다면 제외하기도 함
-> 테스트 용으로 다른 DB를 사용하기도 함
-> DB를 사용하는 테스트는 테스트 과정에서 DB에 테스트 데이터가 적재됨

그래서 DB를 연동한 테스트는 테스트 데이터를 제거하는 코드까지 포함해서 작성하는 것이 좋음!!

하지만 코드가 실행되면서 발생하는 사이드 이펙트 까지 고려시 연동없이 테스트 하는 것이 좋을수도 있음

우선 DB를 제외한 테스트 상황을 가정해 테스트 데이터베이스로 H2 DB 사용

보통 테스트 환경에서는 별도의 설정이 없다면 임베디드 DB 사용

의존성 추가

<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>test</scope>
</dependency>

데이터 베이스 저장 테스트

@DataJpaTest
public class ProductRepositoryTestByH2 {

    @Autowired
    private ProductRepository productRepository;

    @Test
    void saveTest(){
        //given
        Product product = new Product();
        product.setName("펜");
        product.setPrice(1000);
        product.setStock(1000);

        //when
        Product savedProduct = productRepository.save(product);

        //then

        assertEquals(product.getName(), savedProduct.getName());
        assertEquals(product.getPrice(), savedProduct.getPrice());
        assertEquals(product.getStock(), savedProduct.getStock());
    }
}

데이터베이스 조회 테스트

 @Test
    void selectTest(){
        //given
        Product product = new Product();
        product.setName("펜");
        product.setPrice(1000);
        product.setStock(1000);
        
        //객체를 DB에 바로 저장
        Product savedProduct = productRepository.saveAndFlush(product); 
        
        //when
        Product foundProduct = productRepository.findById(savedProduct.getNumber()).get();
        
        //then
        assertEquals(product.getName(), foundProduct.getName());
        assertEquals(product.getPrice(), foundProduct.getPrice());
        assertEquals(product.getStock(), foundProduct.getStock());
    }

@DataJpaTest

JPA와 관련된 설정만 로드해서 테스트 진행

기본적으로 @Transactional 어노테이션을 포함하고 있어 테스트 코드가 종료되면 자동으로 DB의 롤백이 진행!!

기본값으로 임베디드 DB사용 -> 다른 DB를 사용할려면 설정 바꾸자

이 어노테이션을 선언하여 리포지토리를 정상적으로 주입받을수 있음


테스트 DB 변경을 위한 어노테이션 추가

@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class ProductRepositoryTest {
    
    @Autowired
    private ProductRepository productRepository;
    
    @Test
    void save(){
        Product product = new Product();
        product.setName("펜");
        product.setPrice(1000);
        product.setStock(1000);
        
        Product savedProduct = productRepository.save(product);
        
        assertEquals(product.getName(), savedProduct.getName());
        assertEquals(product.getPrice(), savedProduct.getPrice());
        assertEquals(product.getStock(), savedProduct.getStock());
    }
}

replace의 요소는 @AutoConfigureTestDatabase 어노테이션의 값을 조정하는 작업 수행

replace 속성의 기본값은 Replace.ANY 이며 이경우 임베디드 메모리 DB를 사용

None으로 변경 시 실제로 사용하는 DB로 테스트 가능

@SpringBootTest를 통한 테스트

@SpringBootTest
public class ProductRepositoryTest2 {
    
    @Autowired
    ProductRepository productRepository;
    
    @Test
    public void basicCRUDTest(){
        /* create */
        // given
        
        Product givenProduct = Product.builder()
                .name("노트")
                .price(1000)
                .stock(500).build();
        
        //when
        Product savedProduct = productRepository.save(givenProduct);
        
        //then
        Assertions.assertThat(savedProduct.getNumber())
                .isEqualTo(givenProduct.getNumber());
        Assertions.assertThat(savedProduct.getName())
                .isEqualTo(givenProduct.getName());
        Assertions.assertThat(savedProduct.getPrice())
                .isEqualTo(givenProduct.getPrice());
        Assertions.assertThat(savedProduct.getStock())
                .isEqualTo(givenProduct.getStock());
        
        /* read */
        //when
        Product selectedProduct = productRepository.findById(savedProduct.getNumber())
                .orElseThrow(RuntimeException::new);
        
        //then
        Assertions.assertThat(savedProduct.getNumber())
                .isEqualTo(givenProduct.getNumber());
        Assertions.assertThat(savedProduct.getName())
                .isEqualTo(givenProduct.getName());
        Assertions.assertThat(savedProduct.getPrice())
                .isEqualTo(givenProduct.getPrice());
        Assertions.assertThat(savedProduct.getStock())
                .isEqualTo(givenProduct.getStock());
        
        /* update */
        //when
        Product foundProduct = productRepository.findById(selectedProduct.getNumber())
                .orElseThrow(RuntimeException::new);
        
        foundProduct.setName("장난감");
        
        Product updatedProduct = productRepository.save(foundProduct);
        
        //then
        assertEquals(updatedProduct.getName(), "장난감");
        
        /*delete*/
        //when
        productRepository.delete(updatedProduct);

        //then
        assertFalse(productRepository.findById(selectedProduct.getNumber()).isPresent());
    }
}

CRUD 모든 기능을 한 테스트 코드에 작성

@SpringBootTest 어노테이션을 활용하면 스프링의 모든 설정을 가져오고 빈 객체도 전체를 스캔하기에 의존성 주입 고민할 필요 X

다만 테스트 속도가 느림

profile
Journey for Backend Developer
post-custom-banner

0개의 댓글