스프링부트 JUnit으로 테스트 1. JUnit란

min seung moon·2021년 7월 1일
0

Spring

목록 보기
41/50
post-thumbnail

1. JUnit이란?

01. TDD (Test-driven Development)

  • 테스트 주고 개발에서 사용하지만, 코드의 유지 보수 및 운영 환경에서의 에러를 미리 방지하기 위해서 단위 별로 검증 하는 테스트 프레임워크

02. 단위 테스트

  • 작성한 코드가 기대하는 대로 동작 하는지 검증 하는 절차

03. JUnit

  • Java 기반의 단위 테스트를 위한 프레임워크
  • Annotation 기반으로 테스트를 지원하며, Assert를 통하여, (예상, 실제)를 통해 검증

2. Test Project

  • Gradle -> java -> calculator project
    • build.gradle에 junit이 dependencies에 추가되어 있는지 확인
      dependencies {
          testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
          testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
      }
      
      test {
          useJUnitPlatform()
      }

01. 원화 계산기

  • Interface : ICalculator
  • Class : Calculator, KrwCalculator
  • ICalculator.java
public interface ICalculator {

    int sum(int x, int y);
    int minus(int x, int y);
}
  • Calculator.java
public class Calculator {

    private ICalculator iCalculator;

    public Calculator(ICalculator iCalculator) {
        this.iCalculator = iCalculator;
    }

    public int sum(int x, int y) {
        return this.iCalculator.sum(x, y);
    }

    public int mius(int x, int y) {
        return this.iCalculator.minus(x, y);
    }


}
  • KrwCalculator.java
public class KrwCalculator implements ICalculator{

    private int price = 1;

    @Override
    public int sum(int x, int y) {
        x *= price;
        y *= price;
        return x+y;
    }

    @Override
    public int minus(int x, int y) {
        x *= price;
        y *= price;
        return x-y;
    }
}

01. 일일이 테스트하는 미련한 방법

  • Main.java
public class Main {

    public static void main(String[] args) {
        Calculator calculator = new Calculator(new KrwCalculator());

        System.out.println(calculator.sum(10, 10));
        System.out.println(calculator.mius(10, 5));
    }
}

02. 달러 계산기

  • Class : MarketApi, DollorCalculator
  • MarketApi.java
public class MarketApi {

    public int connect() {
        // naver
        // kakao
        return 1100;
    }
}
  • DollorCalculator.java
public class DollorCalculator implements ICalculator{

    private int price = 1;
    private MarketApi marketApi;

    public DollorCalculator(MarketApi marketApi) {
        this.marketApi = marketApi;
    }

    public void init() {
        this.price = marketApi.connect();
    }


    @Override
    public int sum(int x, int y) {
        return 0;
    }

    @Override
    public int minus(int x, int y) {
        return 0;
    }
}
  • Main.java
public class Main {

    public static void main(String[] args) {

        MarketApi marketApi = new MarketApi();
        DollorCalculator dollorCalculator = new DollorCalculator(marketApi);
        dollorCalculator.init();

        Calculator calculator = new Calculator(dollorCalculator);

        System.out.println(calculator.sum(10, 10));
    }
}
  • 결과가 0이 나왔다 코드 중에 실수가 있었다는 건데 일일이 파일을 확인해보는 방법도 있지만 코드간에 의존성이 뻗어있다면 찾기가 힘들기 때문에 다른 방법으로 실수를 찾는다

03. 기본 Test 파일 작성해보기

  • test / java / DollorCalculatorTest.java
import org.junit.jupiter.api.Test;

public class DollorCalculatorTest {

    @Test
    public void testHello() {
        System.out.println("hello");
    }
}


01. Test Code로 문제점 찾기

  • test / java / DollorCalculatorTest.java
    • 코드로 우리가 희망하는 값 "22000"원에 대해서 .sum()의 결과는 0이 나왔다
      • 그럼 문제는 sum() 메소드에 있다는것을 확인 할 수 있다
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class DollorCalculatorTest {

    @Test
    public void testHello() {
        System.out.println("hello");
    }

    @Test
    public void dollorTest() {
        MarketApi marketApi = new MarketApi();
        DollorCalculator dollorCalculator = new DollorCalculator(marketApi);
        dollorCalculator.init();

        Calculator calculator = new Calculator(dollorCalculator);

        System.out.println(calculator.sum(10, 10));

        Assertions.assertEquals(22000, calculator.sum(10, 10));
    }
}



  • DollorCalculator.java
public class DollorCalculator implements ICalculator{

    private int price = 1;
    private MarketApi marketApi;

    public DollorCalculator(MarketApi marketApi) {
        this.marketApi = marketApi;
    }

    public void init() {
        this.price = marketApi.connect();
    }


    @Override
    public int sum(int x, int y) {
        x *= price;
        y *= price;
        return x+y;
    }

    @Override
    public int minus(int x, int y) {
        x *= price;
        y *= price;
        return x-y;
    }
}
  • DollorCalculatorTest.java
    • 코드를 수정하고 나서 꼭 테스트를 통해서 문제가 없는지 다 확인을 해봐야 한다
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class DollorCalculatorTest {

    //@Test
    public void testHello() {
        System.out.println("hello");
    }

    @Test
    public void dollorTest() {
        MarketApi marketApi = new MarketApi();
        DollorCalculator dollorCalculator = new DollorCalculator(marketApi);
        dollorCalculator.init();

        Calculator calculator = new Calculator(dollorCalculator);

        Assertions.assertEquals(22000, calculator.sum(10, 10));
        Assertions.assertEquals(0, calculator.mius(0, 0));
    }
}


04. Mocking(Mockito) 처리

  • Mockito 처리

    • 내가 특정한 객체가 어떤 메소드로 호출이 되었을 때 내가 원하는 결과값을 리턴해 줄 수 있다
    • 실제 객체를 만들어 사용하기에 시간, 비용 등의 Cost가 높거나 혹은 객체 서로간의 의존성이 강해 구현하기 힘들 경우 가짜 객체를 만들어 사용하는 방법이다.
      -테스트 작성을 위한 환경 구축이 어려운 경우
      -테스트가 특정 경우나 순간에 의존적인 경우
      -테스트 시간이 오래 걸리는 경우
      -개인 PC의 성능이나 서버의 성능문제로 오래 걸릴수 있는 경우 시간을 단축하기 위해 사용한다.
    • 출처: https://www.crocus.co.kr/1555 [Crocus]
  • Mockito를 사용하기 위해서는 관련 라이브러리를 추가해 주어야 한다

    • build.gradle
    dependencies {
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
    
        // https://mvnrepository.com/artifact/org.mockito/mockito-core
        testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.9.0'
    
        // https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter
        testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.9.0'
    }


-1. Mock을 활용한 테스트

  • @ExtendWith
    • extension을 등록한다. 이 어노테이션은 상속이 된다. 확장팩이라고 생각하면 될 것 같다.
    • 단위 테스트간에 공통적으로 사용할 기능을 구현하여 @ExtendWith를 통하여 적용할 수 있는 기능을 제공
  • @Mock
    • mock 객체를 생성
    • 실제 객체를 만들기엔 비용과 시간이 많이 들거나 의존성이 길게 걸쳐져 있어 제대로 구현하기 어려울 경우, 가짜 객체를 만들어 사용한다.
  • @BeforeEach
    • 각각의 Test 메소드가 실행될 때 호출되는 메소드(메소드가 실행 전)
    • @BeforeEach는 공통적인 Param 및 설정을 할때 호출되면 좋을 부분
  • DollorCalculatorTest.java
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class DollorCalculatorTest {

    @Mock
    public MarketApi marketApi;

    @BeforeEach
    public void init() {
        // marketApi.connect()가 호출이 되었을 때 3000을 전달
        Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
    }

    @Test
    public void dollorTest() {
        MarketApi marketApi = new MarketApi();
        DollorCalculator dollorCalculator = new DollorCalculator(marketApi);
        dollorCalculator.init();

        Calculator calculator = new Calculator(dollorCalculator);

        Assertions.assertEquals(22000, calculator.sum(10, 10));
        Assertions.assertEquals(0, calculator.mius(0, 0));
    }

    @Test
    public void mockTest() {
        DollorCalculator dollorCalculator = new DollorCalculator(marketApi);
        dollorCalculator.init();

        Calculator calculator = new Calculator(dollorCalculator);

        Assertions.assertEquals(60000, calculator.sum(10, 10));
        Assertions.assertEquals(0, calculator.mius(10, 10));
    }
}


profile
아직까지는 코린이!

0개의 댓글