[Boostcourse] 풀스택/웹 프로그래밍(풀스택)

Spring Test { 빈 객체 테스트, @Runwith, @ContextConfiguration }

Ben의 프로그램 2023. 7. 26. 13:48
728x90
수업목표
지난 시간에는 JUnit 을 이용해 테스트 클래스를 작성하는 방법에 대해서 알아보았습니다. 이번 시간에는 스프링 빈 컨테이너에서 관리하는 빈 객체를 테스트하는 방법에 대해 알아보도록 하겠습니다.

 

기존 프로젝트 수정
이전 시간에 생성했던 CalculatorService 클래스를 스프링 프레임워크에서 Bean 으로 관리되도록 프로젝트를 수정해보겠습니다. 기존 테스트 클래스도 수정하여 Bean 을 테스트하겠습니다.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.edwith.webbe</groupId>
    <artifactId>calculatorcli</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <spring.version>5.2.3.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!-- junit 4.12 라이브러리를 추가합니다. -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- spring-context와 spring-test를 의존성에 추가합니다.-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>

    <!-- 사용할 JDK버전을 입력합니다. JDK 11을 사용할 경우에는 1.8대신에 11로 수정합니다.--><!-- 사용할 JDK버전을 입력합니다. JDK 11을 사용할 경우에는 1.8대신에 11로 수정합니다.-->
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
우선 pom.xml 을 수정하여 JUnit, Spring context, Spring test 라이브러리들을 추가합니다. 

package org.edwith.webbe.calculatorcli;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"org.edwith.webbe.calculatorcli"})
public class ApplicationConfig {
}
그 다음 스프링 프레임워크를 사용하려면 스프링 설정 파일을 작성해야 한다고 배웠었는데요. 스프링 설정 파일은 xml 파일이나 @Configuration & @ComponentScan 애노테이션을 활용한 Java Config 로 작성할 수 있습니다. @Configuration 애노테이션은 스프링 설정 파일이라는 것을 의미하고 스프링 설정 파일은 스프링 빈 컨테이너인 ApplicationContext 에서 읽어 들인다고 했습니다. ( 다음 포스팅 참조 https://benprogram.tistory.com/327 )
@ComponentScan 은 특정 패키지 이하에서만 컴포넌트를 찾도록 제한합니다. @ComponentScan 애노테이션으로 지정된 패키지 이하에 @Component, @Repository, @Service, @Controller, @RestController 등의 애노테이션이 붙은 클래스를 찾아 빈으로 등록하게 됩니다. 

package org.edwith.webbe.calculatorcli;

import org.springframework.stereotype.Component;

@Component
public class CalculatorService {
    public int plus(int value1, int value2) {
        return value1 + value2;
    }

    public int minus(int value1, int value2) {
        return value1 - value2;
    }

    public int multiple(int value1, int value2) {
        return value1 * value2;
    }

    public int divide(int value1, int value2) throws ArithmeticException {
        return value1 / value2;
    }
}
스프링 빈 컨테이너에 빈으로 등록하여 컨테이너가 관리한다는 것은 개발자가 직접 인스턴스를 생성하지 않는다는 것을 의미합니다.(IoC / DI) 스프링 빈 컨테이너가 인스턴스를 생성해서 관리한다는 것을 의미하는데요. 스프링 빈 컨테이너가 CalculatorService 클래스를 찾아 빈으로 등록할 수 있도록 빈으로 지정하고 싶은 클래스 위에 @Component 애노테이션을 붙입니다. 

package org.edwith.webbe.calculatorcli;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args){
        // ApplicationConfig.class 설정파일을 읽어들이는 ApplicationContext객체를 생성합니다.
        // 아래 한줄이 실행되면서 컴포넌트 스캔을 하고, 컴포넌트를 찾으면 인스턴스를 생성하여 ApplicationContext가 관리하게 됩니다.
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);

        // ApplicationContext가 관리하는 CalculatorService.class타입의 객체를 요청합니다.
        CalculatorService calculatorService = applicationContext.getBean(CalculatorService.class);
        
        // ApplicationContext로 부터 받은 객체를 잉요하여 덧셈을 구합니다.
        System.out.println(calculatorService.plus(10, 50));
    }
}
이제 Bean 공장도 만들었고 Bean 으로 생성할 대상도 지정이 끝났습니다. 이제 실제로 사용하는 Main 클래스를 만들어보겠습니다. 위 코드의 실행 결과는 60이 출력됩니다. 

이전 JUnit 테스트 코드에서는 Spring Framework 로 Bean 을 생성해서 관리하지 않았기 때문에 @Before 애노테이션이 붙은 init( ) 메서드에서 CalculatorService 인스턴스를 개발자가 직접 초기화시켜준 것을 확인할 수 있습니다. 스프링 빈 컨테이너가 빈을 생성하고 관리하도록 하고, 그 빈을 테스트할 것이기 때문에 위의 소스 코드를 다음과 같이 수정합니다. 

package org.edwith.webbe.calculatorcli;


import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ApplicationConfig.class})
public class CalculatorServiceTest {
    @Autowired
    CalculatorService calculatorService;

    @Test
    public void plus() throws Exception{
        // given
        int value1 = 10;
        int value2 = 5;

        // when
        int result = calculatorService.plus(value1, value2);

        // then
        Assert.assertEquals(result, 15); // 결과와 15가 같을 경우에만 성공
    }

    @Test
    public void divide() throws Exception{
        // given
        int value1 = 10;
        int value2 = 5;

        // when
        int result = calculatorService.divide(value1, value2);

        // then
        Assert.assertEquals(result, 2); // 결과와 15가 같을 경우에만 성공
    }

    @Test
    public void divideExceptionTest() throws Exception{
        // given
        int value1 = 10;
        int value2 = 0;

        try {
            calculatorService.divide(value1, value2);
        }catch (ArithmeticException ae){
            Assert.assertTrue(true); // 이부분이 실행되었다면 성공
            return; // 메소드를 더이상 실행하지 않는다.
        }
        
        Assert.assertTrue(false); // 이부분이 실행되면 무조건 실패다.
    }
}
@RunWith(SpringJUnit4ClassRunner.class) 애노테이션을 테스트 클래스 위에 붙입니다. @RunWith 애노테이션은 JUnit 이 제공하는 애노테이션인데요. @RunWith 애노테이션은 JUnit 이 테스트 코드를 실행할 때 스프링 빈 컨테이너가 내부적으로 생성되도록 합니다. 그 다음으로 @ContextConfiguration(classes = {ApplicationConfig.class}) 은 내부적으로 생성된 스프링 빈 컨테이너가 사용할 설정파일을 지정할 때 사용니다. 말이 어려운데 결국 이 두 애노테이션을 사용하는 궁극적인 이유는 Bean 컨테이너 환경을 불러와서 @Autowired 를 사용할 수 있게 하는 것입니다. 

이렇게 해서 스프링 빈 컨테이너에서 관리되는 Bean 을 JUnit 테스트에서 사용하는 방법에 대해서 배웠습니다. 

 

출처 : boostcourse 웹 프로그래밍(풀스택) 
https://www.boostcourse.org/web316/lecture/20655?isDesc=false