Junit 5

Angelo·2021년 3월 12일
0

SPRING

목록 보기
24/34

✔ JUnit

자바 프로그래밍용 단위 테스트 프레임워크.


JUnit 5

  • 테스트 작성자를 위한 API 모듈과 실행을 위한 API가 분리되어있음

  • java 8 이상 버전, jdk8 버전 이상에서만 사용 가능

  • Spring Boot 2.2.x 이후 버전부터는 JUnit5를 기본적으로 제공

  • JUnit5는 크게 JUnit Platform, JUnit Jupiter, JUnit Vintage 모듈로 구성되어 있다

    JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform : JVM 기반 테스팅 프레임워크 실행을 위한 기반 모듈, Test를 실행하기 위한 전반적인 사항들을 제공하는 역할
JUnit Jupiter : TestEngine을 구현한 엔진
JUnit Vintage : JUnit3, 4 버전으로 작성된 테스트 코드 실행 시 사용되는 모듈


JUnit Assertions, 부분 정리

assertEquals([message], expected, actual)
: 두 값이 같은 지 비교
assertSame([message], expceted, actual), assertNotSame([message], expceted, actual)
: 두 객체가 동일한 객체인지 비교
assertTrue([message], expceted), assertFalse([message], expceted)
: 참/거짓 판별
assertNull([message], expceted), assertNotNull([message], expceted)
: null여부 판단 fail([message]) 테스트 실패로 판단

JUnit Annotations, 부분 정리

@RunWith : JUnit에서 기본으로 제공하는 러너가 아닌 스프링 러너를 사용하기위한 어노테이션

@SpringBootTest : 테스트에 필요한 모든 설정과 빈들을 자동으로 초기화 하는 역할을 수행

@TEST : 해당 메서드가 테스트 메서드임을 명시

@ParameterizedTest : 매개변수가 있는 테스트 메서드임을 명시

@RepeatedTest : 반복되는 테스트임을 명시

@TestFactory : 동적 테스트임을 명시. 런타임에 생성되는 동적 테스트. 테스트 케이스를 위한 팩토리

@TestTemplate : 여러번 호출 가능한 테스트 템플릿

@TestMethodOrder : 테스트용 메서드 실행 순서 명시

@BeforeEach : 현재 클래스에서 각각의 @Test, @RepeatedTest, @ParameterizedTest, @TestFactory가 있는 메서드들 보다 먼저 실행

@BeforeAll : 모든 테스트 메서드보다 먼저 실행

@AfterAll : 모든 테스트 메서드보다 이후에 실행

@AfterEach : 각각의 테스트 메서드보다 이후에 실행

@DisplayName : 테스트 클래스 or 메서드의 사용자 정의 이름 표시

* 어노테이션 사용, JUnit 테스트 예시 

import org.junit.jupiter.api.*;

import static org.junit.jupiter.api.Assertions.*;

class MyClassTest {
    @Test
    void create() {
        MyClass myclass = new MyClass();
        assertNotNull(myclass);
        System.out.println("create");
    }

    @Test
    @Disabled
    void create1() {
        System.out.println("create1");
    }

    @BeforeAll
    static void beforeAll() {
        System.out.println("before all");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("after all");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("before each");
    }

    @AfterEach
    void afterEach() {
        System.out.println("after each");
    }
}

테스트 가이드 기본 샘플 1

프로젝트 의존성에 테스트 스타터가 등록되어 있기 때문에 테스트에 필요한 여러 라이브러리들도 자동으로 추가.

1. pom.xml JUnit설정

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
	<exclusions>
		<exclusion>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-api</artifactId>
</dependency>

2. 테스트를 적용 시킬 클래스 생성

package kr.co.zikapi.sample.JUnitTest;

public class JUnitSample {
	public int add(int a, int b) {
		return a + b;
	}

	public String hello() {
		return "Hello";
	}

}

3. 테스트케이스 생성

만들었던 클래스를 마우스로 우클릭하고 New의 JUnit Test Case 클릭.

관련 설정과 테스트 원하는 메서드를 선택 할 수 있다.

설정 완료하면 해당 샘플 클래스의 테스트 파일이 생성 된다.
값에 fail("Not yet implemented") 는 생성 시 자동으로 입력되는 값이므로 지우고 테스트 코드를 작성하면 된다.

1. 테스트 코드 작성 전 
package kr.co.zikapi.sample.JUnitTest;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

class JUnitSampleTest {

	@Test
	void testAdd() {
		fail("Not yet implemented");
	}

	@Test
	void testHello() {
		fail("Not yet implemented");
	}
}
2. 테스트 코드 작성 후 
package kr.co.zikapi.sample.JUnitTest;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class JUnitSampleTest {

	@Test
	@DisplayName("1 + 1 = 2")
	void testAdd() {
		JUnitSample jUnitSample = new JUnitSample();
		assertEquals(2, jUnitSample.add(1, 1), "1 + 1 should equal 2");
	}

	@Test
	@DisplayName("헬로우 출력 테스트")
	void testHello() {
		JUnitSample jUnitSample = new JUnitSample();
		assertEquals("Hello", jUnitSample.hello(), "Hello가 출력 되어야함");
	}
}

4. 테스트 실행

테스트 코드가 작성 된 파일을 JUnit 테스트로 실행

성공 시 초록색 :

실패 시 빨강색 :


MockMvc로 컨트롤러 테스트

MockMvc를 이용한 컨트롤러 테스트 예시 링크

테스트 하려는 객체와 비슷한 가짜 객체를 만들어서 테스트에 필요한 기능만 가지도록 모킹을 하면 테스트가 쉬워진다. (Mock 이란 테스트를 위해 만든 모형을 의미)

MockMvc :
요청과 응답을 의미하는 객체, 컨트롤러 테스트를 할 수 있게 해주는 라이브러리.
서버에 배포하지 않고도 스프링 MVC의 동작을 재현할 수 있는 클래스

perform() :
MockMvcRequestBuilders를 사용해 설정한 요청 데이터를 perform()의 인수로 전달, get() / post() / put() / delete() 와 같은 메서드 제공
perform()에서 반환된 ResultActions() 호출

andExpect() :
서버의 응답 결과 검증

status() :
StatusResultMatchers 객체를 리턴. 응답 상태 코드 검증 가능

isOk() :
응답 상태 코드가 200인지 확인

isNotFound() :
응답 상태 코드가 404 NotFound인지 확인

view() :
컨트롤러가 리턴하는 뷰를 검증.
andExpect(view().name("hello")) 는 리턴한 뷰 이름이 "hello"인지 검증

redirectedUrl() :
리턴하는 결과가 리다이렉트 응답일 경우.
andExpect(redirectedUrl("/index")) 는 "/index" 화면으로 리다이렉트 했는지 검증

model() :
컨트롤러에 저장한 모델의 정보들을 검증.
attributeExists(String name)는 name에 해당하는 데이터가 model에 포함되어 있는지 검증.
attribute(String name, Object value)는 name에 해당하는 데이터가 value 객체인지 검증.

andDo() :
생성된 요청과 응답 메시지를 모두 확인해 보고 싶을때 사용.

# 예시

@Test
public void testHome() throws Exception {
    mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(forwardedUrl("/WEB-INF/index.jsp"));
}
  1. @WebMvcTest 사용

: 서블릿 컨테이너를 모킹(테스트용 모형 컨테이너를 사용하기 때문에 간단하게 컨트롤러 테스트 가능)
@Controller, @RestController가 설정된 클래스들을 찾아 메모리에 생성.
@Service나 @Repository가 붙은 객체들은 생성하지 않는다.

  1. @AutoConfigureMockMvc 사용

: @SpringBootTest(webEnvironment=WebEnvironment.MOCK) 설정으로 모킹. 컨트롤러 뿐만 아니라 @Service나 @Repoisotry가 붙은 객체들도 모두 테스트.

@WebMvcTest와 @SpringBootTest는 각자 서로의 MockMvc를 모킹하기 때문에 충돌이 발생할 수 있어 같이 사용 불가하다.


서비스 로직 테스트

컨트롤러에서 단순히 서비스가 제공하는 메소드를 호출하여 사용하는 경우.

@MockBean을 사용하여 특정 타입의 객체를 모킹 해 비즈니스 객체(ServiceImpl)를 생성하지 않고도 테스트 케이스 생성 가능하다.

@Runwith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.Mock)
@AutoConfigureMockMvc
public class ControllerTest {
	@Autowired
   	private MockMvc mockMvc;
    
	@MockBean
	private Service service;
    
	@Test
    public void test() throws Exception {
    	when(service.hello("둘리")).thenReturn("Hello: 둘리");
        
        mockMvc.perform(get("/hello").param("name", "둘리"))
        .andExpect(status().isOk())
        .andExpect(content().string("Hello : 둘리"))
        .andDo(print());
        }
}
profile
나만의 학습 노트

0개의 댓글