TIL(20240705) [테스트코드의 중요성]
TIL(20240705) [테스트코드의 중요성]
📌 테스트코드의 중요성
- 테스트의 부재시 발생하는 문제
- 프로젝트의 규모가 커질수록 간단한 기능 추가 및 수정 시 다른 기능에 어떤 영향을 끼칠 지 알 수 없다.
- 원래 잘 동작하던 기능에도 이상이 생길 수 있다.
- 즉, 어떤 사이드 이펙트가 따라올 지 알 수 없다.
- 복잡한 기능일수록 내가 구현한 코드가 의도한대로 잘 동작하는 지에 대한 검증이 꼭 필요하다.
- 테스트를 포함하게 되면?
- 테스트가 프로젝트의 안정성을 유지해주는 역할을 하기 때문에 새로운 기능을 도입하거나 요구사항에 잘 맞게 리팩토링한 후에도 기존기능이 잘 동작하는지 확인하는 데 도움이 된다.
- 테스트 초반에는 노력과 시간이 필요하다는 단점이 있지만
- 장기적으로 보았을 때 프로젝트 후반까지 코드를 안전하게 확장시킬 수 있다는 점에서 장점이 됩니다.
위와 같이 중요성에 대해서 알아보았는데,
중요성에 대해서 정리해보자면
💡 내가 구현한 코드가 복잡한 기능일수록 의도대로 잘 동작하는지 검증이 꼭 필요하다. 그리고 프로젝트의 규모가 커질수록 간단한 기능 추가 시 사이드 이펙트가 따라올 수 있기에 이러한 상황에 대비하기 위해 test코드를 잘 작성해야한다.
그럼 어떻게 테스트코드를 작성하면 좋은 테스트코드라고 할 수 있을지 알아보자.
🔔 단위테스트
- 단위테스트란? 하나의 기능, 하나의 모듈이 올바르게 잘 동작하고 있는지 확인하는 독립적인 테스트(연관된 객체들을 가짜객체로 대체함)
간단한 Dto나 util클래스는 단위테스트를 작성하게 되면 가치가 0일 확률이 높다.
좋은 단위테스트의 4가지 특성? 1) 회귀방지 -> 기능 오류를 방지 2) 리팩토링 내성 -> 리팩토링 해도 테스트가 깨지지 않음 3) 빠른 피드백 -> 빠른 테스트 속도⭐⭐ 4) 유지보수성 -> 가독성과 재사용서잉 좋고 실행되기 쉽게 작성되어야 함
- 리팩토링 내성을 높이는 방법은 구현 세부사항 대신, 최종결과를 목표로 테스트 코드를 작성하는 것
- 하지만, 테스트코드가 모든 기능 오류를 방지해주는 것은 아니다.
이렇게 좋은 단위테스트의 4가지 특성에 대해서 알아보았고, 각 특성들의 세부적인 것들을 알아보도록 하자.
🚩 빠른 피드백 ?
- 의존성이 없는 코드에 대한 테스트 작성(POJO테스트)
- 의존성을 mock처리하여 핵심 비지니스 로직에 대한 테스트코드만 작성 ex) 복잡한 비지니스 로직이 포함된 service클래스
1
**POJO테스트? Plain Old Java Object로 순수 자바코드로 이루어진 테스트 의미함
📕 Mock 사용하는 경우 ?
- 실제 객체를 만들기에는 비용과 시간이 많이 소요되는 경우
- 의존성이 길게 걸쳐져 있어서 제대로된 테스트 구현이 어려울 경우
- 테스트 작성을 위한 환경구축이 어려운 경우
- 사용방법 mock()/ @InjectMoks, @Mock
1
2
3
4
5
6
7
8
9
10
11
12
public class OrderServiceTest {
private OrderRepository orderRepository = mock(OrderRepository.class);
private ProductRepository productRepository = mock(ProductRepository.class);
private OrderLineRepository orderLineRepository = mock(OrderLineRepository.class);
private OrderService orderService = new OrderService(orderRepository, productRepository, orderLineRepository);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ExtendWith(MockitoExtension.class) // Mock Application Context Load
public class OrderServiceTest {
@Mock
private OrderRepository orderRepository;
@Mock
private ProductRepository productRepository;
@Mock
private OrderLineRepository orderLineRepository;
@InjectMocks
private OrderService orderService;
}
mock()과 @Mock은 동일한 기능을 하지만 @Mock 사용 시, 꼭 test위에 @ExtendWith(MockitoExtension.class) 해당 어노테이션을 붙여주어야 한다.
@MockBean 어노테이션은 뭐지?
- 통합테스트에 쓰이며 실제 Spring Application Context에 올라와있는 Bean을 Mock으로 처리함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@ExtendWith(SpringExtension.class) // 실제 Application Context Load
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductRepository productRepository;
@MockBean
private OrderLineRepository orderLineRepository;
}
@ExtendWith(SpringExtension.class) 어노테이션을 달아주면 @Autowired로 설정된 객체들은 실제 의존성을 주입받지만 @MockBean 어노테이션을 달아주는 객체는 Mock으로 사용하겠다는 의미로, 반환값을 설정해주어야 한다!
This post is licensed under CC BY 4.0 by the author.