1. 통합 테스트 (Integration Test)
- 두 개 이상의 모듈이 연결된 상태를 테스트
- 모듈 간의 연결에서 발생하는 에러 검증 가능
2. 단위 테스트 (Unit Test)
- 하나의 모듈이나 클래스에 대해 세밀한 부분까지 테스트 가능
- 모듈 간에 상호 작용 검증 못함
3. 스프링 부트 이용한 통합 테스트
- 여러 단위 테스트를 하나의 통합된 테스트로 수행
- Controller → Service → Repository
4. "@SpringBootTest" 어노테이션의 이해
- 스프링 부트가 제공하는 테스트 어노테이션.
- 테스트 수행 시 스프링이 동작함
- Spring IoC 사용 가능
- Repository 사용해 DB CRUD 가능
- End to End 테스트도 가능 (강의에서는 실습하지 않음)
- Client 요청 → Controller → Service → Repository → Client 응답
- 테스트의 순서를 정할 수 있음
- @Order(1), @Order(2), ...
5. 관심상품 통합 테스트 설계
- 신규 관심상품 등록
- 회원 Id 는 임의의 값
- 신규 등록된 관심상품의 희망 최저가 변경
- 1번에서 등록한 관심상품의 희망 최저가를 변경
- 회원 Id 로 등록된 모든 관심상품 조회
- 조회된 모든 관심상품 중 1번에서 등록한 관심상품이 존재하는지?
- 2번에서 업데이트한 내용이 잘 반영되었는지?
6.관심상품 통합 테스트 구현
package com.sparta.springcore.integration;
import com.sparta.springcore.dto.ProductMypriceRequestDto;
import com.sparta.springcore.dto.ProductRequestDto;
import com.sparta.springcore.model.Product;
import com.sparta.springcore.service.ProductService;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ProductIntegrationTest {
@Autowired
ProductService productService;
Long userId = 100L;
Product createdProduct = null;
int updatedMyPrice = -1;
@Test
@Order(1)
@DisplayName("신규 관심상품 등록")
void test1() {
// given
String title = "Apple <b>에어팟</b> 2세대 유선충전 모델 (MV7N2KH/A)";
String imageUrl = "https://shopping-phinf.pstatic.net/main_1862208/18622086330.20200831140839.jpg";
String linkUrl = "https://search.shopping.naver.com/gate.nhn?id=18622086330";
int lPrice = 77000;
ProductRequestDto requestDto = new ProductRequestDto(
title,
imageUrl,
linkUrl,
lPrice
);
// when
Product product = productService.createProduct(requestDto, userId);
// then
assertNotNull(product.getId());
assertEquals(userId, product.getUserId());
assertEquals(title, product.getTitle());
assertEquals(imageUrl, product.getImage());
assertEquals(linkUrl, product.getLink());
assertEquals(lPrice, product.getLprice());
assertEquals(0, product.getMyprice());
createdProduct = product;
}
@Test
@Order(2)
@DisplayName("신규 등록된 관심상품의 희망 최저가 변경")
void test2() {
// given
Long productId = this.createdProduct.getId();
int myPrice = 70000;
ProductMypriceRequestDto requestDto = new ProductMypriceRequestDto(myPrice);
// when
Product product = productService.updateProduct(productId, requestDto);
// then
assertNotNull(product.getId());
assertEquals(userId, product.getUserId());
assertEquals(this.createdProduct.getTitle(), product.getTitle());
assertEquals(this.createdProduct.getImage(), product.getImage());
assertEquals(this.createdProduct.getLink(), product.getLink());
assertEquals(this.createdProduct.getLprice(), product.getLprice());
assertEquals(myPrice, product.getMyprice());
this.updatedMyPrice = myPrice;
}
@Test
@Order(3)
@DisplayName("회원이 등록한 모든 관심상품 조회")
void test3() {
// given
// when
List<Product> productList = productService.getProducts(userId);
// then
// 1. 전체 상품에서 테스트에 의해 생성된 상품 찾아오기 (상품의 id 로 찾음)
Long createdProductId = this.createdProduct.getId();
Product foundProduct = productList.stream()
.filter(product -> product.getId().equals(createdProductId))
.findFirst()
.orElse(null);
// 2. Order(1) 테스트에 의해 생성된 상품과 일치하는지 검증
assertNotNull(foundProduct);
assertEquals(userId, foundProduct.getUserId());
assertEquals(this.createdProduct.getId(), foundProduct.getId());
assertEquals(this.createdProduct.getTitle(), foundProduct.getTitle());
assertEquals(this.createdProduct.getImage(), foundProduct.getImage());
assertEquals(this.createdProduct.getLink(), foundProduct.getLink());
assertEquals(this.createdProduct.getLprice(), foundProduct.getLprice());
// 3. Order(2) 테스트에 의해 myPrice 가격이 정상적으로 업데이트되었는지 검증
assertEquals(this.updatedMyPrice, foundProduct.getMyprice());
}
}
- 개발자 테스트 방법 별 장/단점 정리
- 클라이언트 코드에서 호출
- 장점: 실제 서비스를 사용하게 될 고객의 입장에서 기능을 검증해 볼 수 있음
- 단점: 클라이언트 코드 (HTML, CSS, JS) 가 다 작성 되어야만 기능 검증이 가능함
- 프론트 개발과 백엔드 개발이 동시에 진행되고 있다면??
- API 호출앱 사용 (ex. Advanced REST client, Postman)
- 장점: UI 없이 서버의 API 를 손쉽게 검증 가능
- 단점: 여러개의 API 를 한번에 검증하기 어려움
- 스프링의 테스트 프레임워크 사용
- 장점
- UI 없이 서버의 API 를 손쉽게 검증 가능
- 여러개의 API 를 한번에 검증 가능
- 테스트 코드를 소스 코드와 함께 관리 가능
- 코드 수정 후 바로 테스트 가능
- Git 을 이용해 다른 개발자들과 테스트 코드 공유 가능
- 단점
- 테스트 프레임워크에 대한 추가학습이 필요
- 테스트 코드 작성에 다소 시간이 소요
- 장점
- 클라이언트 코드에서 호출
'프로그래밍 > SpringBoot' 카테고리의 다른 글
Spring Data Jpa 페이징 (0) | 2022.06.16 |
---|---|
Spring Data JPA (0) | 2022.06.08 |
Edge 케이스를 고려한 단위 테스트 (0) | 2022.06.06 |
JUnit 테스트란? (0) | 2022.06.06 |
카카오 로그인 구현(2) (0) | 2022.06.03 |