본문 바로가기

Reading Record/토비의 스프링 3.0

1.8 ~ 2.2

 

https://github.com/Java-Bom/ReadingRecord/issues/176

 

[1.8 ~ 2.2] 용어정리 · Issue #176 · Java-Bom/ReadingRecord

XML를 이용해서 Bean 설정 (b7d7163) GenericXmlApplicationContext, ClassXmlApplicationContext GenericXmlApplicationContext 는 xml 패키지 경로를 인자로 주어서 Bean 정보를 가져올 수 있음 ClassXmlApplicationContext 는 인자로 뒤

github.com

XML을 이용한 Bean 설정

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="localDBConnectionMaker" class="com.javabom.toby.userdao.connectionmaker.LocalDBConnectionMaker"/>
    <bean id="testDBConnectionMaker" class="com.javabom.toby.userdao.connectionmaker.TestDBConnectionMaker"/>

    <bean id="userDao" class="com.javabom.toby.userdao.UserDao">
        <property name="connectionMaker" ref="localDBConnectionMaker"/>
    </bean>

    <bean id="dataSourceUserDao" class="com.javabom.toby.userdao.UserDao">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:testdb"/>
        <property name="username" value="test"/>
        <property name="password" value="1234"/>
    </bean>
</beans>

<bean> 태그의 idclass 애트리뷰트를 이용해 빈 정보를 정의할 수 있다.

id 는 빈의 이름 메소드 명으로 등록하면 된다, class는 빈으로 등록할 클래스의 이름으로 등록하면 된다.

<bean id="localDBConnectionMaker" class="com.javabom.toby.userdao.connectionmaker.LocalDBConnectionMaker"/>

위의 bean 설정의 경우 자바 코드로

@Bean
public ConnectionMaker connectionMaker() {
   return new LocalDBConnectionMaker();
}

또한 아래와 같이 setter를 통해 의존관계를 주입해야한다면

public class UserDao {
    private ConnectionMaker connectionMaker;
    
    public void setConnectionMaker(final ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }
}

다음과 같이 property 태그를 통해 의존관계를 정의할 수 있다.

<bean id="userDao" class="com.javabom.toby.userdao.UserDao">
        <property name="connectionMaker" ref="localDBConnectionMaker"/>
    </bean>

만약 다음 DataSource와 같이 DB 설정 정보를 지정하고 Bean으로 만들어야 할 경우 

@Bean
public DataSource dataSource() {
    SimpleDriverDataSource dataSource = new SimpleDriverDataSource();

    dataSource.setDriverClass(org.h2.Driver.class);
    dataSource.setUrl("jdbc:h2:mem:testdb");
    dataSource.setUsername("test");
    dataSource.setPassword("1234");

    return dataSource;
}

XML에선 property 태그의 value 애트리뷰트를 이용해서 값을 지정해 주면 된다.

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:testdb"/>
        <property name="username" value="test"/>
        <property name="password" value="1234"/>
    </bean>

 

XML Application Context

Application Context가 XML 설정정보를 활용하도록 하려면 GenericXmlApplicationContextClassPathXmlApplicationContext를 사용하면 된다.

ApplicationContext genericContext = new GenericXmlApplicationContext("applicationContext.xml");
UserDao genericDao = genericContext.getBean("userDao", UserDao.class);

ApplicationContext classPathContext = new ClassPathXmlApplicationContext("classPathContext.xml", UserDao.class);
UserDao classPathDao = classPathContext.getBean("userDao", UserDao.class);

 

GenericXmlApplicationContext는 생성자 파라미터로 XML 설정 파일의 클래스패스를 지정해주면 된다.

ClassPathXmlApplicationContext는 두번째 파라미터로 특정 클래스를 지정하면, 해당 클래스의 클래스패스 부터 상대경로로 XML 설정 파일을 지정할 수 있다.

XML 파일 경로

 

단위 테스트, 포괄적인 테스트

public class Car {
    private static final int MOVE_CONDITION = 4;
    private int distance;

    public Car(final int distance) {
        this.distance = distance;
    }

    public int move(String value) {
        if (isMovable(Integer.parseInt(value))) {
            distance++;
        }

        return distance;
    }

    private boolean isMovable(int value) {
        return MOVE_CONDITION < value;
    }
}

4 이상의 값이 들어왔을때 자신의 distance 값을 1 증가시키고 distance 값을 리턴하는 Car라는 클래스에 대해 테스트를 한다고 하자.

단위테스트는 특정 메소드가 의도된대로 정확하게 동작하는지 테스트하는 것을 얘기한다.

즉, 위의 move라는 메소드가 4이상의 값이 들어왔을때 distance값이 증가하거나, 그 반대의 경우 증가하지 않는 것을 테스트하는 것이다.

class CarTest {

    @DisplayName("4 보다 큰 값일때 distance값을 증가시킨다.")
    @ParameterizedTest
    @ValueSource(strings = {"5", "6", "7"})
    void move(String value) {
        Car car = new Car(3);
        assertThat(car.move(value)).isEqualTo(4);
    }

    @DisplayName("4 이하의 값일때 distance값은 증가하지 않는다.")
    @ParameterizedTest
    @ValueSource(strings = {"4", "3", "2"})
    void cannotMove(String value) {
        Car car = new Car(3);
        assertThat(car.move(value)).isEqualTo(3);
    }
    
}

여기서 위의 테스트의 경우 무조건적으로 성공할 수 밖에 없는 테스트이다. move 메소드의 경우 인자로 String 값을 받아 int로 변환시키고 값을 비교하는데 만약 숫자가 아닌 값이 들어온다면 int형으로 변환하는 과정에서 Exception이 생기게 될 것이다.

따라서 테스트 대상에 대해 모든 상황을 테스트 하는 것을 포괄적인 테스트라 한다.

class CarTest {

    @DisplayName("4 보다 큰 값일때 distance값을 증가시킨다.")
    @ParameterizedTest
    @ValueSource(strings = {"5", "6", "7"})
    void move(String value) {
        Car car = new Car(3);
        assertThat(car.move(value)).isEqualTo(4);
    }

    @DisplayName("4 이하의 값일때 distance값은 증가하지 않는다.")
    @ParameterizedTest
    @ValueSource(strings = {"4", "3", "2"})
    void cannotMove(String value) {
        Car car = new Car(3);
        assertThat(car.move(value)).isEqualTo(3);
    }

    @DisplayName("숫자가 아닌 값이 들어오면 Exception Throw")
    @ParameterizedTest
    @ValueSource(strings = {"a", "b", " ", "+"})
    void exceptionThrowWhenNotNumber(String notNumber) {
        Car car = new Car(1);
        assertThatThrownBy(() -> car.move(notNumber))
                .isInstanceOf(NumberFormatException.class);
    }
}