자바 개발자의 93%가 사용하는 단위 테스트 프레임워크. 스프링 부트 2.2버전 이상 부터는 기본적으로 제공됨.
JUnit5 모듈
Platform : 테스트를 실행해주는 런처 제공. TestEngine API 제공
Jupiter : JUnit5를 지원하는 TestEngine API구현체
Vintage : JUnit4와 3를 지원하는 TestEngine 구현체
(*작성한 버전에 따라 Jupiter를 사용하거나 Vintage를 사용한다.)
Annotation 사용법
@Test
테스트라는 것을 나타내는 어노테이션
// JUnit4
@Test(expected = Exception.class)
void create() throws Exception {}
// JUnit5
@Test
void create(){}
@BeforeAll
해당 클래스에 위치한 모든 테스트 메서드 실행전에 딱 한번 실행된다.
@AfterAll
해당 클래스에 위치한 모든 테스트 메서드 실행 후에 딱 한번 실행된다.
@BeforeEach
해당 클래스에 위치한 모든 테스트 메서드 실행 전에 실행되는 메서드
(*매 테스트 메서드마다 새로운 클래스를 생성하여 실행(비효율적))
@AfterEach
해당 클래스에 위치한 모든 테스트 메서드 실행 후에 실행되는 메서드
(*매 테스트 메서드마다 새로운 클래스를 생성하여 실행(비효율적))
@Disabled
테스트를 하고 싶지 않은 클래스나 메서드에 붙이는 어노테이션
@DisplayName
어떤 테스트인지 쉽게 표현할 수 있도록 해주는 어노테이션
공백, emoji, 특수문자 등을 모두 지원
@RepeatedTest
틀정 테스트를 반복 시키고 싶을 때 사용하는 어노테이션
반복 횟수와 반복 테스트 이름을 설정 가능
성능상의 이슈를 확인할때 사용한다.
@RepeatedTest(10)
@DisplayName("반복테스트")
void repeatedTest(){}
@RepeatedTest(value=10, name="{**displayName**}중 {**currentRepetition**} of {**totalRepetitions**})
@DisplayName("반복테스트")
void repeatedTest2(){}
@ParameterizedTest
테스트에 여러 다른 매개변수를 대입해가며 반복 실행할 때 사용하는 어노테이션
@ParameterizedTest
@CsvSource(value={"ACE,ACE:12", "ACE,ACE,ACE:13", "ACE,ACE,TEN:12"}, delimiter=':')
@DisplayName("에이스 카드가 여러 개일 때 합 구하기")
void calculatedCardSum(final String input, final int expected){
final String[] inputs = input.split(",");
for(final String number : inputs){
final CardNumber cardNumber = Cardnumber.valueOf(number);
dealer.receiveOneCard(new Card(cardNumber, CardType.CLOVER));
}
assertThat(dealer.calculateSource()).isEqualTo(expected); // 마지막에 CsvSource와 비교한다.
}
@Nested
테스트 클래스 안에서 내부 클래스를 정의해 테스트를 계층화 할 때 사용
내부클래스는 부모클래스의 멤버 필드에 접근가능
Before/After와 같은 테스트 생명주기에 관계된 메소드들도 계층에 맞춰 동작
Assertions
테스트 케이스의 수행 결과를 판별하는 메서드로 모든 Junit Jypiter Assertions는 static메서드다.
(*static이란 공유개념과 같아서 여러 객체가 하나의 메모리를 참조하여 값을 공유한다. → 효율적인 메모리 사용가능. 즉, static으로 메소드를 선언했을때 인스턴스없이 해당 메모리로 접근하여 호출이 가능해진다.)
assertAll
@Test
public void create_study(){
Study study = new Study();
assertNotNull(study);
assertEquals(Status.STARTED, study.getStatus(), "처음 상태값이 DRAFT");
// 만약 여기서 실패한다면 원래는 아래의 assertTrue가 실행되지 않는다.
assertTrue(study.getLimit() > 0, () -> "최대 인원은 0보타 커야한다.")
}
@Test
public void create_study(){
Study study = new Study();
assertAll( // 중간에 실패한 assertion이 있어도 전부 실행한다.
()->assertNotNull(study),
()->assertEquals(Status.STARTED, study.getStatus(), "처음 상태값이 DRAFT"),
()->assertTrue(study.getLimit() > 0, () -> "최대 인원은 0보타 커야한다.")
);
}
assertThrows
@Test(expected = Exception.class)
void create() throws Exception{}
@Test
void excptionTrow(){
Exception e = **assertThrows**(Exception.class, ()-> new Test(-10));
assertDoesNotThrow(()->System.out.println("Do Something"));
}
assertTimeout
특정시간 안에 실행이 완료되는지 확인가능하다.
Assumption
전제문이 true라면 실행, false라면 종료한다.
assumeTrue : false일 때 이후 테스트 전체가 실행되지 않는다.
assumingThat : 파라미터로 전달된 코드블럭만 실행되지 않는다.
void dev_env_only(){
assumeTrue("DEV".equals(System.getenv("ENV")), ()->"개발환경이 아닙니다.");
//위의 가정이 false라면 이후 코드가 실행되지 않는다.
assertEquals("A","A");
}
void some_test(){
assumingThat("DEV".equals(System.getenv("ENV")),
()->{
assertEquals("A","A"); //해당 단정문만 실행되지 않는다.
});
assertEquals("A","A"); // 위의 가정과 상관없이 무조건 실행된다.
}
실제 코드를 적용해보자
간단하게 파라미터로 해당 값을 더해주고 리턴하는 REST API가 존재한다. 이때 Test코드를 짜보자.
@RestController
public class TestController {
@GetMapping("/add")
public int add(@RequestParam int A, @RequestParam int B){
return A+B;
}
}
@AutoConfigureMockMvc // MockMvc에 필요한 주입을 한다.
@SpringBootTest // 테스트에 필요한 거의 모든 의존성을 제공한다.
public class TestControllerTest {
// MockMvc는 웹 어플리케이션을 애플리케이션 서버에 배포하지 않고
// 테스트용 MVC환경을 만들어 요청 및 전송, 응답기능을 제공해주는 유틸리티 클래스다
@Autowired
private MockMvc mockMvc;
@Test
public void addTest() throws Exception {
// 준비
String url = "/add?A=1&B=2";
// 실행
final ResultActions actions = mockMvc.perform(MockMvcRequestBuilders.get(url)
.contentType(MediaType.APPLICATION_JSON));
// 단언
actions.andExpect(result->{
MockHttpServletResponse response = result.getResponse();
System.out.println(response.getContentAsString());
assertEquals("3",response.getContentAsString());
});
}
}
래퍼런스
https://www.youtube.com/watch?v=EwI3E9Natcw&t=191s
https://wikidocs.net/228#static_1
https://velog.io/@jkijki12/Spring-MockMvc
'개발' 카테고리의 다른 글
JAVA의 스레드를 공부하자 (0) | 2022.02.26 |
---|---|
[TDD] 자바와 JUnit을 활용한 실용주의 단위 테스트 (작성중) (0) | 2022.02.24 |
JAVA의 Servlet이 뭐지? (0) | 2022.02.19 |
JAVA 인터페이스는 왜 쓰는 걸까? (0) | 2022.02.18 |
OOP(Object-Oriented Programming, 객체 지향 프로그래밍)이 머냐? (0) | 2022.02.16 |