테스트 코드의 중요성
테스트 코드는 개발 과정에서 매우 중요하다. 이를 통해 버그를 조기에 발견하고 소프트웨어의 안정성을 확보할 수 있다.
특히, 스프링부트에서는 다양한 도구와 라이브러리를 제공하여 테스트 코드 작성을 쉽게 도와준다.
이런 도구들을 효율적으로 사용함으로써, 개발자는 애플리케이션의 다양한 부분을 효율적으로 검증하고,
결과적으로 코드의 품질을 높일 수 있다.
또한, 테스트 코드는 리팩토링과 기능 추가 시 안정성을 제공해 주기 때문에, 유지 보수성을 크게 향상시켜준다.
JUnit 5
`JUnit 5`는 스프링부트에서 가장 많이 사용되는 테스트 프레임워크 중 하나이다.
이 프레임워크는 `@Test` 어노테이션을 사용해 테스트 메서드를 정의하고, 테스트 실행 전과 후에 특정 작업을 수행할 수 있도록
`@BeforeEach`, `@AfterEach`, `@BeforeAll`, `@AfterAll` 같은 어노테이션을 제공한다.
`JUnit 5`의 큰 장점 중 하나는 태그, 필터링, 맞춤형 테스트를 지원한다는 것이다.
이를 통해 복잡한 테스트 환경을 관리하고, 더 효율적인 테스트 실행 전략을 구성할 수 있다.
또한, 람다를 사용한 강력한 `Assertion` 기능을 제공해 예외 테스트와 같은 고급 테스트 케이스를 쉽게 작성할 수 있다.
- `@BeforeAll`
- `@BeforeAll`을 사용하는 메서드가 현재 테스트 클래스의 모든 메서드(테스트)보다 먼저 실행된다.
- `@AfterAll`
- `@AfterAll`을 사용하는 메서드가 현재 테스트 클래스의 모든 메서드(테스트)의 이후에 실행된다.
- `@BeforeEach`
- `@BeforeEach`는 각 테스트 실행 전에 초기화 작업을 수행한다.
- `@AfterEach`
- `@AfterEach`는 테스트 후에 정리 작업을 수행한다.
코드 예시
public class SampleTest {
private SomeClass someClass;
@BeforeEach
void setUp(){
someClass = new SomeClass();
}
@Test
void testSomeMethod() {
assertEquals("expected", someClass.someMethod());
}
@AfterEach
void tearDown(){
someClass = null;
}
}
Mockito
`Mockito`는 단위 테스트를 위한 목 객체 생성 프레임워크다.
실제 의존성을 가짜 객체로 대체하는 기능을 제공하므로, 의존성이 복잡한 클래스를 단순화시켜 테스트할 수 있도록 도와준다.
예를 들어, 데이터베이스 연결이나 외부 서비스 호출과 같은 부분을 목 객체로 대체하면,
이러한 외부 요소들의 영향 없이 클래스의 기능을 순수하게 테스트할 수 있다.
`Mockito`는 가짜 객체 생성, 메서드 호출에 관한 `Stub` 설정, 호출 검증 및 메서드 호출에 대한
모의 행동을 정의하는 등 많은 기능을 제공한다.
이러한 기능들은 복잡한 애플리케이션의 단위 테스트를 간소화하고, 테스트 코드의 가독성과 유지보수성을 크게 향상시켜 준다.
코드 예시
`Mockito`를 사용해 `Dependency` 클래스의 목 객체를 생성한다.
`when().thenReturn()` 구문을 사용해 목 객체의 행동을 정의한다.
이렇게 하면 실제 의존성 대신 `Mock` 객체가 적용되어 테스트를 수행한다.
아래 코드에서는 `dependency.method()`가 동작하면 "mocked value"라는 문자열 값을 리턴하게 했다.
public class MockTest {
@Mock
private Dependency dependency;
private SomeClass someClass;
@BeforeEach
void setUp(){
MockitoAnnotations.initMocks(this);
someClass = new SomeClass(dependency);
}
@Test
void testMethodUsingMock(){
when(dependency.method()).thenReturn("mocked value");
assertEquals("mocked value", someClass.useDependency());
}
}
AssertJ
`AssertJ`는 테스트 코드의 `assertion`(프로그램 안에 추가하는 참, 거짓을 미리 가정)을 위한 강력한 라이브러리다.
`JUnit`의 기본 `assertion`보다 훨씬 풍부한 기능을 제공해서, 테스트 코드를 더 가독성 있고 유지보수하기 쉽게 만들어준다.
`AssertJ`의 주요 특징 중 하나는 체인 형식의 API를 제공한다는 것이다. 이 API는 다양한 타입에 대한 광범위한 `assertion`을 지원해서, 개발자가 보다 명확하고 자연스러운 방식으로 테스트 조건을 표현할 수 있도록 해준다.
예를 들어, 문자열, 컬렉션, 숫자 등 다양한 타입에 관한 세밀한 테스트를 수행할 수 있다.
이런 기능들 덕분에 `AssertJ`는 테스트 코드의 표현력과 가독성을 크게 향상시키는 데 도움을 준다.
코드 예시
`AssertJ`는 체인 형식의 API를 제공하여, 테스트 조건을 보다 자연스럽고 가독성 높게 표현할 수 있게 해준다.
아래 코드처럼 `assertThat()` 메서드를 사용하면 다양한 `assertion`을 체인 형식으로 연결할 수 있다.
public class AssertJTest {
@Test
void testWithAssertJ(){
assertThat("someString").isEqualTo("someString");
assertThat(Arrays.asList("one", "two")).contains("one");
}
}
SpringBootTest
`@SpringBootTest` 어노테이션은 스프링 부트 애플리케이션의 전체 컨텍스트를 로드하여 통합 테스트를 수행하는 데 사용된다.
이는 실제 애플리케이션을 실행하는 것과 유사한 환경에서 테스트를 할 수 있게 해준다.
따라서, 애플리케이션의 다양한 부분들이 서로 어떻게 상호작용하는지를 효과적으로 테스트할 수 있게 해준다.
(실제와 가장 비슷)
하지만, 전체 스프링 컨텍스트를 로드하는 것은 테스트 실행 시간을 길게 만들 수 있다.
그래서, 때로는 필요한 컴포넌트만 선택적으로 로드하는 방식을 적용하면 테스트의 실행 속도를 향상시키고,
더 효율적인 테스트 전략을 구성할 수 있다.
코드 예시
`@SpringBootTest` 어노테이션은 스프링 부트의 전체 애플리케이션 컨텍스트를 테스트 동작시에 로드한다.
이를 통해 실제 애플리케이션 환경에서 서비스나 컴포넌트가 올바르게 로드되고 작동하는지 테스트할 수 있다.
(최적화를 안하면 테스트를 할 때 너무 많은 `SpringBoot` 서버가 동작하니 주의하자.)
@SpringBootTest
class SomeServiceTest {
@Autowired
private SomeService someService;
@MockBean
private MyRepository myRepository;
@Test
void contextLoads() {
assertNotNull(someService); // someService가 컨텍스트에서 로드되었는지 확인
}
}
주의할 점은 스프링 부트의 전체 애플리케이션 컨텍스트를 로드하므로, `Repository`에 문제가 있으면 오류가 발생한다.
TDD(Test-Driven Development)
`TDD`, 즉 테스트 주도 개발은 테스트 코드를 먼저 작성하고, 이를 통과하는 실제 코드를 그다음에 작성하는 개발 방법론이다.
이 접근 방식의 주요 장점은 설계 개선, 코드 품질 향상, 그리고 리팩토링의 용이성에 있다.
`TDD`를 통해 개발자는 더 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있고, 테스트 코드 자체가 문서화의 역할을 하게 된다.
이 방법론은 개발 초기 단계부터 버그를 줄이고, 지속적인 피드백을 통해 소프트웨어의 품질을 지속적으로 개선할 수 있게 해준다.
`TDD`를 통한 개발은 다들 프로젝트에 적용해야 한다고 생각은 하지만 적용시키지 못한다.
특히, `SI` 기업에서는 빠르게 개발하는 것을 목표로 하다보니 경험해 볼 기회가 더 적어진다.
`TDD`는 익숙해지려면 꾸준한 연습이 필요하니 사전 연습이 많이 필요하다.
'Spring > Test' 카테고리의 다른 글
[테스트 코드] 스프링에서의 Redis 테스트 환경 구축 (0) | 2024.11.29 |
---|---|
[테스트 코드] @DataJpaTest 사용 (0) | 2024.11.24 |
[테스트 코드] 테스트 코드에서 static method를 사용하는 법 (0) | 2024.11.24 |
[테스트 코드] 단위 테스트 @InjectMock 사용방법 (0) | 2024.11.24 |
[테스트 코드] MockMvc, MockBean (0) | 2024.11.21 |