Junit
Junit 이란?
java 진영의 대표적인 test Framework
단위 테스트를 위한 도구를 제공
- 단위 테스트란?
- 코드의 특정 모듈이 의도된 대로 동작하는지 테스트 하는 절차를 의미
- 모든 함수와 메소드에 대한 각가의 테스트 케이스를 작성하는것
- 어노테이션을 기반으로 테스트를 지원
- 단정문으로 테스트 케이스의 기대값에 대해 수행 결과를 확인할 수 있음
- Spring boot 2.2.버전부터 junit5 버전을 사용
- Junit 5는 크게 Jupiter,Platfrom,Vintage 모듈로 구성
모듈 설명
Junit Jupiter
TestEngine api 구현체로 Junit 5를 구현하고 있다.
테스트의 실제 구현체는 별도 모듈 역할을 수행하는데, 그 모듈 중 하나가 jupiter-engine 이다.
이 모듈은 jupiter-api를 사용하여 작성한 테스트 코드를 발견하고 실행하는 역할을 수행
개발자가 테스트 코드를 작성할 때사용된다.
Junit Platfrom
Test를 실행하기 위한 뼈대
테스트를 발견하고 테스트 계획을 생성하는 TestEngine 인터페이스를 가지고 있다.
TestEngine을 통해 Test를 발견하고, 수행 및 결과를 보고함
그리고 각종 ide 연동을 보조하는 역할을수행
Vintage
TestEngine api의 구현체로 junit3,4를 구현하고 있다
Junit의 특징
- JUnit은 자바용 단위 테스트 작성을 위한 표준 프레임 워크이다.
- xUnit이라는 단위 테스트 프레임워크의 자바 구현물이다.
- 테스트 도구이며 외부 테스트 프로그램을 작성해 할 필요 없이 이를 관리해줄 수 있다
- 하나의 jar파일로 되어있으며 사용법 또한 간단하다.
- 테스트 결과를 확인하는 것 뿐만 아니라 최적화된 코드를 유추하는 기능이 있다 성능향상을 기대할 수 있다.
- Test클래스를 통해 다른 개발자에게 테스트 방법과 클래스 히스토리를 알려줄 수 있다.
통합 테스트
통합 테스트는 여러 기능을 조합하여 전체 비즈니스 로직이 제대로 동작하는지 확인하는 것을의미
통합테스트의 경우 @SpringbootTest를 사용하여 진행
- 모든 빈을 로드하기때문에 프로젝트가 커질 수록 무겁다.
단위 테스트
단위테스트는 프로젝트에 필요한 모든 기능에 대한 테스트를 각각 진행하는 것을 의미
JUnit에서 테스트를 지원하는 어노테이션 (라이프 사이클)
- @Test
- @Test가 선언된 메서드는 테스트를 수행하는 메소드가 된다.
- JUnit은 각각의 테스트가 서로 영향을 주지 않고, 동립적으로 실행됨을 원칙으로 하며. @Test마다 객체를 생성한다.
- @Ignore
- @Ignore가 선언된 메서드는 테스트를 실행하지 않는다.
- @Before
- @Before 가 선언된 메서드는 @Test 메서드가 실해되기 전에 반드시 실행된다.
- @Test 메서드에서 공통으로 사용하는 코드를 @Before 메서드에 선언하여 사용하면 된다.
- @After
- @After 가 선언된 메서드는 @Test 메서드가 실행된 후에 실행된다.
- @BeforeClass
- @BeforeClass 어노테이션 @Test 메서드보다 먼저 한번만 수행되어야 할 경우에 사용된다.
- @AfterClass
- @AfterClass 어노테이션은 @Test 메서드보다 나중에 한번만 수행되어야 할 경우에 사용된다.
주로 사용하는 JUnit 메서드
assertEquals(a,b) : 객체 a,b의 값이 일치하는 지 확인
assertArrayEquals(a,b) : 배열 a,b의 값이 일치하는지 확인
assertSame(a,b) : 객체 a, b 가 같은 객체인지를 확인 두 객체의 레퍼런스가 동일한지 확인
assertTrue(a) : 조건 a가 참인가를 확인
assertNotNull(a) : 객체 a가 null이 아님을 확인
Spring-Test 어노테이션
- @RunWith(SpringJUnit4ClassRunner.class)
- @RunWith 어노테이션을 사용함으로써, JUnit에 내장된 러너를 사용하는 대신 어노테이션에 정의된 러너 클래스를 사용
- JUnit 프레임워크의 테스트 실행방법을 확장할 때 사용하는 어노테이션이다.
- @RunWith를 사용하기 위해선 JUnit 실행에 필요한 SpringJUnit4ClassRunner 클래스를 상속받은 @RunWith(SpringRunner.class)를 꼭 붙여서 사용해야 한다.
- @RunWith 어노테이션은 각각의 테스트 별로 객체가 생성되더라도 싱글톤(Singletone)의 ApplicationContext를 보장한다.
- @RunWith 어노테이션은 JUnit4에서 주로 사용하는 것으로 알고 있고, JUnit5의 경우에는 @ExtendWith를 사용한다.
- @ContextConfiguration
- 스프링 빈(Bean) 설정 파일의 위치를 지정할 때 사용하는 어노테이션이다.
- @SpringBootTest
- 통합 테스트를 제공하는 기본적인 스프링 부트 테스트 어노테이션이다.
- 애플리케이션에 설정된 빈을 모두 로드하기 때문에 규모가 클 수록 느려지는 단점이 있다.
- 빈을 로드할때 test용 application context를 만들어 Bean을 추가하고 MockBean을 찾아 교체한다.
- @ExtencWith
- JUnit4에서 @RunWith로 사용되던 어토에이션이 해당 어노테이션으로 변경됐다.
- 메인으로 실행될 클래스를 지정할 수 있다.
- @SpringBootTest에 기본적으로 추가 돼 있다.
- 기존에 테스트파일은 스프링과 관련없는 독립적인 클래스 파일인데 이를 스프링환경으로 만들어주는 어노테이션이다.
- @WebMvcTest
- MVC를 위한 테스트 어노테이션이다.
- 웹에서 테스트하기 힘든 Controller를 테스트하는 데 적합하고 웹 상의 요청 또는 응답에 대해 테스트할 수 있다.
- @WebMvcTest를 사용하면 MVC 관련 설정인 어노테이션만 불러오기 때문에 @SpringBootTest보다 가벼운 테스트가 가능
- @Autowired and
- 컨트롤러의 api를 테스트하는 용도로 MockMvc객체를 주입받는다
- perform()메소드를 사용해서 컨트롤러의 동작을 확인할 수 있다.
- .andExpect(),andDo(),AndReturn() 등의메소드를 같이 활용
- @Mockbean
- 테스트할 클래스에서 주입받고 있는 객체에 대해 가짜 객체를 생성해주는 어노테이션
- 해당 객체는 실제 행위를 하지 않는다.
- given()메소드를 활용해서 가짜 객체의 동작에 대해 정의하여 사용할 수 있다.
- @AutoConfigureMockMvc
- spring.test.mockmvc 의 설정을 로드하면서 MockMvc의 의존성을 자동을 ㅗ주입
- MockMvc 클래스는 Rest API를 테스트 할 수 있는 클래스
- @Import
- 필요한 클래스들을 Configuration으로 만들어 사용할 수 있다.
- @DataJpaTest
- JPA 관련 테스트 설정만 로드하는 어노테이션이다.
- 데이터 소스의 설정이 정상적인지 JPA를 사용하여 데이터를 제대로 CRUD 하는지 테스트가 가능하다.
- @Entity 어노테이션을 스캔하여 Spring Data JPA 저장소를 구성한다.
- 실제 데이터 베이스 공간을 사용하지 않고, 내장형 데이터 베이스 공간을 사용하여 테스트하기 때문에 JPA 테스트 이후 실제 데이터 베이스가 변경 되었는지 걱정할 필요가 없다.
- @RestClientTest
- REST 관련 테스트를 도와주는 어노테이션이다.
- REST 통신의 데이터 형식으로 주로 사용되는 JSON 형식에 대해서 제대로 응답을 반환하는지 등을 테스트 한다.
- @Json Test
- JSON 테스트를 지원하는 어노테이션이다.
- @JsonTest 어노테이션은 JSON의 직렬화와 역직렬화를 수행하는 라이브러리인 Gson과 Jackson API 테스트를 제공한다.
mockito
- MockMvc
- 해당 객체를 테스트시에 주입받아서 사용하면 실제 http요청을 프로그램 단에서 구현할 수 있다.
- perform 으로 테스트하고자 하는 api의 http 메소드를와 자원주소를 작성해서 요청을 보낸것처럼 테스트를 해 볼 수 있다.
ex) Controller
컨트롤러를 테스트할때 기본적으로 해당 컨트롤러에서 주입받은 service를 사용하는것은 테스트코드가 실제 의존성에 영향이 있기때문에 @MockBean 을 사용해서
해당 서비스의 구현체를 모킹한다.
given
@MockBean을 통해서 등록된 목객체가 특정 상황에서 해야하는행위를 정의하는 메소드 이다. nestjs에 spy나 jest.fn()같은 역할을 한다.
Ex)
//컨트롤러를 테스트할때 의존돼있는 서비스를 모킹해서 모킹된 함수를 호출하고, 그 호출파라미터값과 그 파라미터값에 대한 기댓값또한(return값)개발자가 정해줄 수 있다.
given(productService.getProduct("123")).willReturn(new ProductDto("1233","name",4000,4044));
// 호출하는 목함수의 리턴값은 실제 리턴값과 맞춰줘야한다.
// 이렇게 하면 실제로 db에서 가져오지않고 가짜로 값을 가져오는것이 되는것이다.
perform
- get, delete
- 넘겨줄 데이터가없기때문에 그냥 해당 자원주소에 요청을 하면된다(given등을 사용해서 사전작업을 다 했다면)
- post, update,put
- 넘겨줄 바디데이터에 대한 컨텐트타입, 그리고 바디 데이터를 담아서 보내야한다.
- content() : () 안에 바디데이터 넣는다
- contentType() : MediaType을 사용해서 마임타입을 ()안에 넣는다.
- andExpect() : 기대한값이 나왓는지 체크하는메서드
- jsonPath: 리턴으로 받는 제이슨데이터의 바디값에 대한 기대값에 유무를 체크할 수 있다.
- andDo: 테스트 결과 이후의 행동을 지정한다(print()를 사용하면 테스트 이후의 결과 출력)
- verify: 해당 객체의 메소드가 실행되었는지 체크해준다
- verify(productService).getProduct("123");
- mockito.when 어떠한 경우를 입력하고
- thenReturn : when에 경우에대한 리턴값 설정
BDDMockito 란?
위와같이 단순하게 given, when, then 이 세가지 함수를 지원해주는 라이브러리이다.
JSON 데이터로 변환하기
new ObjectMapper().writeValueAsString(오브젝트);
- 오브젝트로 다시 바꿀려면 read
~함수를 쓰면된다.
테스트 방법
예를 들어 AService를 테스트한다고 할때 실제 AService에서 등록하는 빈만 테스트에 등록하면 AService를 테스트 할 수 있게된다.
이렇게 필요한 빈만 띄어서 테스트를 작성하는것을 단위테스트라고 하는데 이는 필요한 빈만 등록하기때문에 빠르게 테스트를 돌려볼수 있다는 장점이있지만
실제 서버에서 서비스를할때 잘 작동할것이라는 보장은 할 수 없다 왜냐하면 분리해서 테스트했으니까 다른곳에서 영향을 미칠 수 있기때문이다.
그래서 전체가 잘 돌아가지는지에 대한 테스트는 통합테스트를 해야하는것이다.
service 단위 테스트정리
@ExtendWith(MockitoExtension.class)로 스프링환경을 띄어준 후에,해단 단위테스트에서 di하는 객체들 메모리에 띄우면 된다.
하지만이때 di돼있는 진짜 객체를 띄우면 실제 환경에 의존되기때문에 실제 객체를 사용하지 않는다.
@InjectMocks 를 사용해서 해당 객체에 @Mock로 등록된 모든 객체를 주입받는다.
Repository 단위 테스트정리
@DataJapTest를 사용하면 jpa 관련된 애들과 Repository를 메모리에 띄운다.
그리고 실제 db를 사용할것인지 가짜 db를사용할것인지에 대한 설정은
@AutoConfigureTestDatabase(replace=Replace.ANY) 를사용해서 가짜 디비로 테스트를 할 수 있고, NONE은 실제 db 로 테스트한다.
@Transactinal을 붙여준다.
그리고 테스트하는 레파지톨리를 @Autowired로 di를 한다.
Controller 단위 테스트
@WebMvcTest로 필요한 객체만 메모리에 등록하고 MockMvc를 di한다. 그리고 해당 컨트롤러에서 di돼 있는 서비스나 다른 객체들을 가짜로
@MockBean으로 가짜 빈등록을 한다. 가짜객체는 빈껍때기이기때문에 다음과같이 생명력을 불어넣는다고 생각하면된다.
given으로 준비를하고
when으로 행동을 지정한다.(thenReturn())
그리고 mockMvc.perform(httpMethod("주소").contentType("MIME").content(body))
또한 ResultActions타입으로 mockMvc에대한 결과를 받을 수 있다.
then으로 검증한다.
- andExpect() : 기대한값이 나왓는지 체크하는메서드
- jsonPath: 리턴으로 받는 제이슨데이터의 바디값에 대한 기대값에 유무를 체크할 수 있다.
- andDo: 테스트 결과 이후의 행동을 지정한다(print()를 사용하면 테스트 이후의 결과 출력)
- verify: 해당 객체의 메소드가 실행되었는지 체크해준다
- verify(productService).getProduct("123");
통합테스트 정리
@SpringbootTest를 하면 모든 빈이 메모리에 뜬다.(빈이많을수록 오래걸림.)
@SpringbootTest를 사용할때는 webEnvironment.MOCK 옵션을 사용하면 실제 톰켓을 올리는 것이아니라 다른 톰켓으로 테스트 하는것이고
webEnvironment.RANDOM_PORT는 실제 톰켓으로 테스트 하는것
그리고 mockMvc를 메모리에 띄어서 서버 요청에대한 테스트를 한다.이때 모키토를 di를 하려면 @AutoConfigureMockMvc 가 있어야하는데 WebMvcTest가 들고있다.
@Trancavtional을 사용해서 각각의 테스트함수가 종료될때마다 트랜젝션을 rollback해주는 어노테이션
통합테스트는 postman사용하듯이 하면돼서 간단하다.
tip 문자열 리턴값 테스트
MvcResult requestResult = resultAction.andReturn();
String result = getResponse().getContentAsString();
'Springboot' 카테고리의 다른 글
Spring boot-Cache Control Headers 하는법 (0) | 2023.08.14 |
---|---|
JPA 복합키 작성기초 (0) | 2023.08.14 |
@Deprecated와 @deprecated (0) | 2023.08.14 |
@Transactional원리 (0) | 2023.08.14 |
Spring boot AOP (0) | 2023.08.14 |