목적 : 지속되는 변경에 테스트 코드에 의해 보호를 받알 수있음
테스트 코드만 보고도 기능 명세가 될 수 있음
https://martinfowler.com/articles/microservice-testing/#conclusion-test-pyramid
단위테스트 : 도메인별로 테스트
https://dancerscode.com/posts/unit-tests/
sut : system under test (테스트 대상, 주로 하나의 클래스)
테스트 버블 : 협력관계에 있는 객체를 바로 실제 객체에 사용할 수 없을때 가짜로 만드는것
예: stop, mock객체
컴포넌트테스트 : 서비스 전체
통합테스트(Intergration test) : 테스트하고자하는코드를 다른의존관계와 연동이 잘 됬는지
외부시스템과 연동도 잘 되는지
엔드투엔드 :UI부터 Api호출, DB에 적재 되는지등 시스템 전체에 대한 테스트
매 단위 테스트시마다 테스트 클래스의 인스턴스가 생성되어 독립적인 테스트가 가능
애노테이션을 제공해서 테스트 라이프 사이클을 관리하게 해주고 테스트 코드를 간결하게 작성하도록 지원(@afterall, @aftereach)
테스트 러너를 제공해서 인텔리제이 / 이클립스 / 메이븐 등에서 테스트 코드를 쉽게 실행 가능
assert로 테스트 케이스의 수행 결과를 판별하게 해줍니다. →assertEquals(예상 값, 실제값)
결과는 성공(녹색), 실패(붉은색) 중 하나로 표시해줍니다.
1,2번 테스트를 위해 resources에 logback-test.xml 작성
@BeforeAll - 테스테에 한번만 실행
@BeforeEach - 테스트마다 실행
3. assertEqual : 기댓값과 실행값이 일치한지 확인해 주는 기능
4. 할인된 금액이 일치하는지 테스트
5. 마이너스가 될 경우 예외를 던져줘야하는데 그거에 대한 코드가 없기때문에 오류가 뜬다
5,6,7 테스트를 위해 FixedAmountVoucher에다가 각각 경우에 대해 예외처리해주는 코드를 추가해준다.
7번에 @Disabled는 해당 테스트를 건너뛰는 효과가 있음
더 편리한 테스트를 제공해주는 Hamcrest 이용
- Hamcrest을 사용하기 위해 임포트 해줘야함
- 기존에 사용했던 assertEquals대신에 assertThat 사용
- equalTo, is : 결과값이 2 여야한다
- anyOf : 결과값이 2 이거나 1
- 컬렉션에 대해 테스트 할 수 있도록 편리한 기능 제공
- hasSize : 리스트의 크기
- gresterThan: 모든 값이 1을 넘는가?
- containsInAnyOrder: 순서에 상관없이 해당값들을 포함하고 있는가?
- hasItem: 해당값을 가지고 있는가 ?
greatherThanOrEqyalTo가 있으므로 2보다 크거가 같은 값을 가지고있는가?
실제값과 기대값을 매칭
햄클래스
2.OrderServiceTest 작성
- Stub 이용
- Mock 이용 (import static org.mockito.Mockito.*;)
- voucherService와 OrderRepository에 대한 Mock 생성
- mock은 when으로 기술한 부분만 동작함
voucherServiceMock객체에서 우리가 만든 fixedAmountVoucher 에 아이디를 가지고 올라하면 fixedAmountVoucher가 리턴되는 상황을 만들었다.- 오더서비스를 만들고 오더서비스를 우리가 테스트 하는 내용을 실행
오더에대한 사태검증 할수 있고 오더서비스안에서 사용되는 바우처서비스가 어떤 행동을 하는지 어떤 메서드가 호출이 되는지를 검증을함- 특정한순서를 보장해서 수행되어 져야 한다면, inOrder을 이용하면 각각의 목들이 어떤 순서대로 호출되어져야하는지까지 판단 가능
Inorder을 추가함으로써 OrderService에서 작성한 순서대로 수행이 되어야함. 만약에 순서가 바뀐다면, 오류가 뜸
우리는 목오브젝트의 도움을 받아서 별도의 코드추가없이 메서드 호출여부 확인할수있고 어떻게 동작이 수행이 되어지는지 확인이 가능
@SpringJUnitConfig
@ActiveProfiles("test")
public class kdtSpringContextTests {
@Configuration
@ComponentScan(basePackages = {"org.prgrms.kdt.order", "org.prgrms.kdt.voucher"})
static class Config{
}
@Autowired
ApplicationContext context;
@Autowired
OrderService orderService;
@Autowired
VoucherRepository voucherRepository;
@Test
@DisplayName("applicationContext가 생성 되어야한다. ")
public void testApplicationContext(){
assertThat(context, notNullValue());
}
@Test
@DisplayName("VoucherRepository가 빈으로 등록 되어야한다 . ")
public void testVoucherRepositoryCreation(){
var bean = context.getBean(VoucherRepository.class);
assertThat(bean, notNullValue());
}
@Test
@DisplayName("orderService를 사용해서 주문을 생성 할 수 있다. ")
public void testOrderService(){
//Given
var fixedAmountVoucher = new FixedAmountVoucher(UUID.randomUUID(),100);
voucherRepository.insert(fixedAmountVoucher);
//When
var order = orderService.createOrder(UUID.randomUUID(), List.of(new OrderItem(UUID.randomUUID(),200,1)),fixedAmountVoucher.getVoucherId());
//Then
assertThat(order.totalAmount(),is(100L)); //totalAmount 값이 Long 이기 때문에 Long타입으로 변환
assertThat(order.getVoucher().isEmpty(), is(false));
assertThat(order.getVoucher().get().getVoucherId(), is(fixedAmountVoucher.getVoucherId()));
assertThat(order.getOrderStatus(),is(OrderStatus.ACCEPTED));
}
}
- 이전에는 Mock을 이용했다면 통합테스트는 applicationContext에서 빈들을 꺼내어 테스트 applicationcontext 를 만들어줌
- @SpringJUnitConfig를 이용해 TestContextFramework이 만들어짐
두개를 포함하고 있음
@ExtendWith(SpringExtension.class)
@ContextConfiguration /(classes = {AppConfiguration.class})- @ActiveProfiles("test") 를통해 맞는 레포지토리 프로파일 엑티브
- @ComponentScan을 통해 각각의서비스와 레포지토리를 빈에 등록