본문 바로가기

Spring이론

spring boot에서 test code 작성(TDD, Junit)

반응형

이번엔 이론편으로 돌아왔습니다.

제가 현재 spring boot를 통해 제작중인 서버를 만드는데 있어서 이제는 test code를 제작할 필요가 생겼다는 판단으로 

test code 제작 방법을 공부하고 있습니다.

 

Spring으로 개발을 하면서 test를 만들지 않는다면 spring이 지닌 가치의 절반을 포기하는 셈이라고 합니다.

spring 개발자로서 test 작성방법과 이를 효과적으로 개발에 활용하는 전략을 알아야 하고, 이를 실전에 적용하기 위해 

오늘의 글 작성을 시작해보겠습니다.

* 아래 나올 내용은 https://youtu.be/SFVWo0Z5Ppo 어라운드 허브 스튜디오의 영상과 토비의 스프링을 참조했습니다.

 

1. TDD

테스트 주도 개발이라는 의미를 지니고 있습니다.

simple하게 말하자면 TDD란 test를 먼저 설계 및 구축 후 test를 통과할 수 있는 code를 짜는 것으로 

code 작성 후에 test를 진행해왔던 지금까지 사용했던 방식과는 차이점이 있습니다.

 

test code를 작성하게 된다면 code의 안정성을 높일 수 있고

기능을 추가하거나 변경하는 과정에서 발생할 수 있는 Side-effect를 줄일 수 있습니다.

또한 code에 불필요한 내용이 들어가는 것을 비교적 줄일 수 있으며 해당 code가 작성된 목적을 명확하게

표현할 수 있습니다.

 

2. JUnit

Java 진영의 대표적인 Test Framework로 Unit Test를 위한 tool을 제공합니다.

Annotation을 긱반으로 test를 지원하며 Assert로 test case의 기댓값에 대해 결과를 확인합니다.

Spring Boot 2.2 version 부터는 JUnit 5를 사용하는데 

JUnit 5는 크게 Jupiter, Platform, Vintage module로 구성되어 있습니다.

 

2.1 Junit Framework

framework는 개발자가 만든 class에 대한 제어 권환을 넘겨 받아서 주도적으로 application의 흐름을 제어합니다.

개발자가 만든 class의 object를 생성하고 실행하는 일은 framework에 의해 진행됩니다.

따라서 framework에서 동작하는 code는 main() method도 필요 없고 object를 만들어서 실행시키는 code를 만들 필요도 없습니다.

 

Junit Frame work의 경우

1. method가 public으로 선언돼야 합니다.

2. method에 @Test라는 annotation을 붙여야 합니다.

 

2.2 Unit Test

Unit test란 code의 특정 module이 의도된 대로 test하는 절차를 의미합니다.

모든 method에 대한 각각의 test case를 작성하는 것입니다.

일반적으로 spring boot에서는 'org.springframework.book:spring-boot-starter-test' dependency만으로 

의존성을 모두 가질 수 있습니다.

 

2.3 Assert

test code에서는 if문 대신에 JUnit이 제공해주는 assertThat이라는 static method를 이용해야 합니다.

ex) 

assertThat(user2.getName(), is(User.getName()));

 

assertThat() method는 첫 번째 parameter의 값을 뒤에 나오는 matcher라고 불리는 조건으로 비교해서 일치하면 

다음으로 넘어가고, 아니면 test가 실패하도록 만들어 줍니다.

is()는 matcher의 일종으로 equals를 비교해주는 기능을 가졌습니다.

 

2.4 JUnit Jupiter

TestEngine API의 구현체로 JUnit 5를 구현하고 있습니다.

test의 실제 구현체는 별도로 module 역할을 수행하는데, 그 module 중 하나가 Jupiter-Engine으로

이 module은 Jupiter-API를 사용하여 작성한 test code를 발견하고 실행하는 역할을 수행하여

개발자가 test code를 작성할 때 사용됩니다.

 

2.5 JUnit Platform

test를 실행하기 위한 뼈대로 test를 발견하고 test 계획을 생성하는 TestEngine interface를 갖고 있습니다.

TestEngine을 통해 test를 발견하고, 수행 및 결과를 보고합니다.

그리고 각종 IED 연동을 보조하는 역할을 수행합니다.

 

3. JUnit LifeCycle Annotation

3.1 Annotation

@Test

- test용 method를 표현하는 annotation

 

@BeforeEach

각 테스트 메소드가 시작되기 전에 실행되어야 하는 메소드를 표현

 

@AfterEach

각 테스트 메소드가 시작된 후 실행되어야 하는 메소드를 표현

 

@BeforeAll

테스트 시작 전에 실행되어야 하는 메소드를 표현(static 처리 필요)

 

@AfterAll

테스트 종료 후에 실행되어야 하는 메소드를 표현(static 처리 필요)

 

3.2 JUnit의 test 수행 방식

1. test class에서 @Test가 붙은 public이고 void형이며 parameter가 없는 test method를 모두 찾습니다.

2, test class의 object를 하나 만듭니다.

3. @Before가 붙은 method가 있으면 실행합니다.

4. @Test가 붙은 method를 하나 호출하고 test 결과를 저장해둡니다.

5. @After가 붙은 method가 있으면 실행합니다.

6, 나머지 test method에 대해 2~5번을 반복합니다.

7. 모든 test의 결과를 종합해서 돌려줍니다.

 

4. JUnit Main Annotation

@SpringBootTest

- 통합 test 용도로 사용됩니다.

- @SpringBootAplication을 찾아가 하위의 모든 Bean을 스캔하여 로드하고

   testApplication Context를 만들어 Bean을 추가하고, MockBean을 찾아 교체합니다.

 

*통합테스트는 여러 기능을 조합하여 전체 비즈니스 로직이 제대로 동작하는지 확인하는 것을 의미합니다.

 이 방법을 대규모 프로젝트에서 사용할 경우, 테스트를 실행할 때마다 모든 빈을 스캔하고 로드하는 작업이 반복되어 매번  무거운 작업을 수행해야 합니다.

 

 

@ExtendWith

- JUnit4에서 @RunWith로 사용되던 어노테이션이 ExtendWith로 변경되었습니다.

- @ExtendWith는 메인으로 실행될 Class를 지정할 수 있습니다.

- @SpringBootTest는 기본적으로 @ExtendWith가 추가되어 있습니다.

 

@WebMvcTest(Class.class)

-()에 작성된 클래스만 실제로 로드하여 테스트를 진행

- 매개변수를 지정해주지 않으면 @Controller, @RestController, @RestControllerAdvice 등 컨트롤러와 연관된 Bean이 모두 로드됩니다.

- 스프링의 모든 Bean을 로드하는 @SpringBootTest 대신 컨트롤러 관련 코드만 테스트할 경우 사용합니다.

 

@Autowired about Mockbean

- controllerapi를 테스트하는 용도인 mockMvc객체를 주입받습니다.

- perform()메소드를 활용하여 컨트롤러의 동작을 확인할 수 있습니다.

.andExpect(), andDo(), andReturn()등의 메소드를 같이 활용합니다.

 

@Import

- 필요한 class들을 configuration으로 만들어 사용할 수 있습니다.

- configuration component 클래스도 의존성 설정할 수 있습니다.

- import된 클래스는 주입으로 사용가능합니다.

 

다음번에는 test code를 만드는 실습편에서 찾아 뵙겠습니다.

반응형