JUnit, Coverage

duckbill413·2023년 1월 21일
0

Spring boot

목록 보기
5/8
post-thumbnail

JUnit

  • TDD(Test-driven development): 테스트 주도 개발에서 사용하지만, 코드의 유지 보수 및 운영 환경에서의 에러를 미리 방지 하기 위해서 단위 별로 검증 하는 테스트 프레임워크
  • 단위테스트: 작성한 코드가 기대하는 대로 동작을 하는지 검증 하는 절차
  • JUnit: Java 기반의 단위 테스트를 위한 프레임워크 Annotation 기반으로 테스트를 지원하며, Assert를 통하여, (예상, 실제)를 통해 검증

[Mockito 사용법]

1. Mock 객체 의존성 주입

Mockito에서 Mock(가짜) 객체의 의존성 주입을 위해서는 크게 3가지 어노테이션이 사용된다.

  • @Mock: Mock 객체를 만들어 반환해주는 어노테이션
  • @Spy: Stub하지 않은 메소드들은 원본 메소드 그대로 사용하는 어노테이션
  • @InjectMocks: @Mock 또는 @Spy로 생성된 가짜 객체를 자동으로 주입시켜주는 어노테이션

2. Stub로 결과 처리

  • doReturn(): Mock 객체가 특정한 값을 반환해야 하는 경우
  • doNothing(): Mock 객체가 아무 것도 반환하지 않는 경우(void)
  • doThrow(): Mock 객체가 예외를 발생시키는 경우

⚠️ @ExtendWith(MockitoExtension.class) : Mockito 테스팅 프레임워크를 JUnit과 결합하기 위한 어노테이션 사용

JUnit실습

  • Assertion.assertEquals(expected, result) : 결과 값과 예상 값을 비교하여 검사
  • @ExtendWith(MockitoExtension.class) 모킹 test
    • Mocking 이란:
      Mocking은 테스트하려는 코드에 외부 의존성이 있을 때 단위 테스트에서 사용되는 프로세스다.
      모킹을 함으로서 실제 객체를 대체 객체로 대체한다. 대체 객체에는 fake, stub, mock 세 가지 유형이 있다.
      • fake

        fake는 동일한 인터페이스를 구축하지만 다른 객체와 상호작용하지 않고 실제 코드를 대체하는 객체다.
        보통 fake는 고정된 결과를 반환하도록 하드 코딩된다. 다양한 유즈케이스를 테스트하려면 많은 페이크를 사용해야 한다.
        fake의 문제는 인터페이스가 수정되면, 이 인터페이스를 수정하는 fake도 수정해야 한다는 것이다.

      • stub

        stub는 특정 인풋 셋을 기반으로 특정 결과를 반환하는 객체다. 일반적으로 테스트를 위해 프로그래밍 항목 이외의 항목에는 응답하지 않는다.

      • mock

        mock은 stub의 좀 더 정교한 버전이다. 각 메서드를 몇 번 째 호출하는지에 따라 프로그래밍할 수 있다. 어떤 데이터를 응답할건지 설정할 수 있다.

      • Mockito dependency 필요

        testImplementation group: 'org.mockito', name: 'mockito-core', version: '4.8.0'

      • Mockito JUnit

        testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: '4.6.1'

  • 예제 코드 - Mocking 사용
    @ExtendWith(MockitoExtension.class)
    public class DollarMockingTest {
        @Mock
        public MarketApi marketApi;
    
        @BeforeEach
        public void init(){
            Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
        }
    
        @Test
    		@DisplayName("Dollar sum/minus test")
        public void mockTest(){
    //        MarketApi marketApi = new MarketApi(); //MEMO: MOCK활용을 위하여 삭제
    DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
            dollarCalculator.init();
    
            Calculator calculator = new Calculator(dollarCalculator);
            System.out.println(calculator.sum(10, 10));
            //MEMO: Assertions를 활용한 검사
    Assertions.assertEquals(60000, calculator.sum(10, 10));
            Assertions.assertEquals(0, calculator.minus(10, 10));
        }
    }
    • Mocking 사용을 위하여 @ExtendWith(MockitoExtension.class) 어노테이션을 붙인다.
    • Mocking을 위하여 MarketApi@Mock Annotation을 붙인다.
    • Mockito.lenient().when 으로 marketApi.connet() 에서 3000원 리턴
  • WebMvcTest 하기
    @WebMvcTest(CalculatorApiController.class)
    @AutoConfigureWebMvc
    @Import({Calculator.class, DollarCalculator.class})
    public class CalculatorApiControllerTest {
    
        @MockBean
        private MarketApi marketApi;
    
        @Autowired
        private MockMvc mockMvc;
    
        @BeforeEach
        public void init() {
            Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
        }
    
        @Test
        public void sumTest() throws Exception {
            // http://localhost:8080/api/sum
            mockMvc.perform(
                    MockMvcRequestBuilders.get("http://localhost:8080/api/sum")
                            .queryParam("x", "10")
                            .queryParam("y", "10")
            ).andExpect(
                    MockMvcResultMatchers.status().isOk()
            ).andExpect(
                    MockMvcResultMatchers.content().string("60000")
            ).andDo(MockMvcResultHandlers.print());
        }
    
        @Test
        public void minusTest() throws Exception {
            Req req = new Req(10, 10);
            String json = new ObjectMapper().writeValueAsString(req);
            mockMvc.perform(
                            MockMvcRequestBuilders.post("http://localhost:8080/api/minus")
                                    .contentType(MediaType.APPLICATION_JSON)
                                    .content(json)
                    ).andExpect(
                            MockMvcResultMatchers.status().isOk()
                    ).andExpect(
                            MockMvcResultMatchers.jsonPath("$.result").value("0")
                    ).andExpect(
                            MockMvcResultMatchers.jsonPath("$.response.resultCode").value("OK")
                    )
                    .andDo(MockMvcResultHandlers.print());
        }
    }
    1. @WebMvcTest(CalculatorApiController.class) Anotation 등록
    2. @AutoConfigureWebMvc ← Spring Mvc test를 위하여 등록
    3. @Import({Calculator.class, DollarCalculator.class}) ← 사용할 클래스 불러오기(이미 Bean 등록이 되어있어 생략 가능)
    4. 값을 fake할 클래스를 @MockBean으로 등록
    5. Web Test를 대신하기 위하여 MockMvc 불러오기

📌 MockMvc를 이용하여 Spring Web Testing 하기

  • perform : 테스트 실행하기 MockMvcRequestBuilders 로 Request Builder
  • andExpect: 예상값과 결과값을 비교 MockMvcResultMatchers 메소드 이용
  • andDo: 테스트 실행하고 할 일을 등록
    ex) MockMvcResultHandlers.print() 실행 과정 출력

Test Coverage

Jacoco

Java 코드의 코드 커버리지를 체크 하는 라이브러리

결과를 html, xml, csv 로 확인 가능하다.

📌 Java Gradle plugins에 jacoco를 추가

plugins{
    id 'jacoco'
}
  • jacocoTestCoverageVerification
  • jacocoTestReport

Gradle → Tasks → verification에 추가된다.

  • Gradle → Tasks → verification 의 test를 클릭하여 테스트 가능

  • 테스트 결과는 build/reports/tests/test/index.html 에 저장되고 chrome 등으로 열어 확인 가능하다.

  • jacocoTestReport 역시 비슷하게 실행 가능
    build/reports/jacoco/test/html/index.html 에서 결과 report 확인 가능

profile
같이 공부합시다~

0개의 댓글