개발공부/Spring Boot

[Spring Boot] JUnit으로 테스트하기

환타몬 2022. 3. 13. 17:01
  • TDD (Test-driven Development)

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

 

  • 단위 테스트

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

 

  • JUnit

Java기반의 단위 테스트를 위한 프레임워크

Annotation 기반으로 테스트를 지원하며, Assert를 통하여 (예상, 실제)를 통해 검증

 

 

우선 테스트할 코드를 작성해보자.

 

 - 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 minus(int x, int y){
        return this.iCalculator.minus(x, y);
    }
}

- MarketApi.java

public class MarketApi {

    public int connect(){
        return 1100;
    }
}

 

- DollarCalculator.java

public class DollarCalculator implements ICalculator{

    private int price = 1;
    private MarketApi marketApi;

    public DollarCalculator(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;
    }
}

 

- ICalculator.java

public interface ICalculator {

    int sum(int x, int y);
    int minus(int x, int 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;
    }
}

 

- Main.java

public class Main {

    public static void main(String arg[]){
        System.out.println("hello JUnit");
        MarketApi marketApi = new MarketApi();

        DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
        dollarCalculator.init();

        //ICalculator를 상속받은 클래스를 주입
        Calculator calculator = new Calculator(dollarCalculator);

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

    }
}

 

 

이 클래스들과 함께 코드를 실행하면 우리가 원하는 값인 달러 값으로 나오지 않는데, 그 이유는

Calculator에 주입된 dollarCalculator에 작성된 sum 메서드가 비어있기 때문이다.

 

우리는 이와 같은 문제를 알아보기 위해서 main에서 계속 올라가는 방법을 사용했었는데, 이제는 JUnit을 이용해서 테스트 해보려고 한다.

 

아래 그림과 같이 main이 아닌 test폴더에 java로 들어간 후 DollarCalculatorTest.java 를 생성한다.

 

- DollarCalculator.java

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

public class DollarCalculatorTest {

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

    @Test
    public void dollar(){

        MarketApi marketApi = new MarketApi();

        DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
        dollarCalculator.init();

        //ICalculator를 상속받은 클래스를 주입
        Calculator calculator = new Calculator(dollarCalculator);
        System.out.println(calculator.sum(10,10));

        //Assertions의 assertEquals를 이용해서 기대값과 출력값을 비교할 수 있음.
        Assertions.assertEquals(22000, calculator.sum(10,10));
        Assertions.assertEquals(0,calculator.minus(10,10));
    }


}

 

DollarCalculator.java의 sum, minus 메서드의 내용을 아래와 같이 수정한다.

@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;
}

 

또한 모킨처리라고 해서 어떤 객체가 메서드로 호출됐을 때 내가 원하는 결과 값을 리턴시킬 수 있는 것이 있다.

이것을 간단하게 표현해보면 아래와 같이 나온다.

 

- DollarCalculatorTest.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.junit.jupiter.api.extension.Extensions;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

// 목킨처리
// 내가 특정한 객체가 어떤 메소드로 호출됐을 때 내가 원하는 결과값을 리턴시킬 수 있음
@ExtendWith(MockitoExtension.class)
public class DollarCalculatorTest {

    @Mock
    public MarketApi marketApi;

    @BeforeEach
    public void init(){
        // markeyApi의 connect가 호출이 될 때 3000이란 값을 return함.
        Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
    }

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

    @Test
    public void dollarTest(){

        MarketApi marketApi = new MarketApi();

        DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
        dollarCalculator.init();

        //ICalculator를 상속받은 클래스를 주입
        Calculator calculator = new Calculator(dollarCalculator);
        System.out.println(calculator.sum(10,10));

        //Assertions의 assertEquals를 이용해서 기대값과 출력값을 비교할 수 있음.
        Assertions.assertEquals(22000, calculator.sum(10,10));
        Assertions.assertEquals(0,calculator.minus(10,10));
    }

    @Test
    public void mockTest(){
        DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
        dollarCalculator.init();

        //ICalculator를 상속받은 클래스를 주입
        Calculator calculator = new Calculator(dollarCalculator);
        System.out.println(calculator.sum(10,10));

        //Assertions의 assertEquals를 이용해서 기대값과 출력값을 비교할 수 있음.
        Assertions.assertEquals(60000, calculator.sum(10,10));
        Assertions.assertEquals(0,calculator.minus(10,10));
    }


}