spring 의 유닛 테스트 전략

본 고 는 주로 spring 이 제공 하 는 Junit 확장 메커니즘 을 사용 하여 단원 테스트 를 진행 하 는데 디자인 mock 방면 의 테스트 가 없다 는 것 을 소개 한다.
1.Spring 에서 제공 하 는 JUnit 프레임 워 크 확장:
1.AbstractSpringContextTests:spring 에서 spring 컨 텍스트 테스트 를 사용 하 는 Junit 확장 류 는 일반적으로 이 종 류 를 사용 하여 유닛 테스트 를 하지 않 습 니 다.이것 은 spring 내부 디자인 에 사용 되 는 클래스 입 니 다.
2.AbstractDependency InjectionSpringContextTests:이것 은 AbstractSpringContextTests 의 직접 하위 클래스 입 니 다.spring 컨 텍스트 에 의존 하 는 테스트 클래스 를 지원 합 니 다.이 클래스 는 사 무 를 지원 하지 않 습 니 다.
3.AbstractTransactionalSpringContextTests:이것 은 AbstractDependency Injection SpringContextTests 의 직접 하위 클래스 입 니 다.이 종 류 는 일반적으로 사무 와 관련 된 테스트 에 사 용 됩 니 다.모든 테스트 가 완료 되면 정상적으로 스크롤 백 사 무 를 수행 하고 데이터 베 이 스 를 업데이트 하지 않 습 니 다.사무 와 관련 된 작업 을 수 동 으로 설정 하려 면onSetUpInTransaction 과 onTearDownInTransaction 방법 을 다시 불 러 올 수 있 습 니 다.수 동 으로 업 무 를 시작 하고 제출 하거나 setComplete()방법 을 호출 할 수 있 습 니 다.이 종 류 는 사무 가 없 는 상태 에서 도 이 종 류 를 사용 할 수 있다.
4.AbstractTransactionalDataSourceSpringContextTests:AbstractTransactionalSpringContextTests 의 직접 하위 클래스 입 니 다.Spring 의 JDBC 기반 jdbcTemplate 도구 류 를 사용 하여 데이터베이스 등급 의 업 무 를 지원 합 니 다.
저 는 계승 순서에 따라 위의 네 가지 유형 을 소개 합 니 다.구체 적 으로 spring 의 api 문 서 를 참고 하거나 spring 의 소스 코드 를 읽 을 수 있 습 니 다.간단 한 코드 입 니 다.
2.테스트 전략:
다음은 실제 프로젝트 의 간략화 버 전 으로 예 를 들 어 구체 적 인 디 렉 터 리 경 로 를 테스트 합 니 다.
test
    --system
        --dao
            --UserDAOImplTest.java
            ......
        --service
            --UserServiceImplTest.java
            ......
        --AbstractSystemTest.java
        --testSystemContext.xml
    --manage
        --dao
            --CustomerDAOImplTest.java
            ......
        --service
            --CustomerServiceImplTest.java
            ......
        --AbstractManageTest.java
        --testSystemContext.xml
    --testApplicationContext.xml
설명:
test 는 테스트 경로 입 니 다.system 과 manage 는 모듈 이름 입 니 다.각 모듈 의 단원 테스트 클래스 는 이 클래스 를 계승 합 니 다).그 다음 에 층 을 나 누 는 경로 입 니 다.여 기 는 DAO 와 service 층 입 니 다.모든 DAO 와 service 단원 테스트 클래스 를 포함 합 니 다.저 희 는 총 spring 프로필 testApplication Context.xml 이 있 습 니 다.아무리 많은 해석 을 해도 코드 가 가장 뚜렷 하지 않 고 다음은 일부 예시 코드 이다
testApplicationContext.xml

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>jdbc.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        <property name="url">
            <value>${jdbc.url}</value>
        </property>
        <property name="username">
            <value>${jdbc.username}</value>
        </property>
        <property name="password">
            <value>${jdbc.password}</value>
        </property>
    </bean>

    <bean id="parentSessionFactory" abstract="true"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.Oracle9Dialect
                </prop>
                <prop key="hibernate.cache.provider_class">
                    org.hibernate.cache.EhCacheProvider
                </prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.cglib.use_reflection_optimizer">
                    true
                </prop>
            </props>
        </property>
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
    </bean>

    <!-- transaction -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="baseTransactionProxy"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
        abstract="true">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="*">
                    PROPAGATION_REQUIRED, -ApplicationException
                </prop>
                <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="list*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>
    </bean>

    <!-- Base DAO -->
    <bean id="baseDAO" abstract="true"
        class="com.mycompany.myproject.framework.BaseDAOImpl">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

모든 spring 의 기본 설정 파일 을 여기에 넣 었 습 니 다.저 는 spring 이 제공 하 는 설정 기법 을 교묘 하 게 추상 적 인 parentSession Factory 를 설명 한 다음 에 모든 하위 모듈 의 session Factory 가 이 대상 을 계승 하도록 했 습 니 다.그러면 중복 되 는 배치 파일 을 많이 줄 였 습 니 다.
testSystemContext.xml

    <bean id="sessionFactory" parent="parentSessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="mappingDirectoryLocations">
            <list>
                <value>
                    com/mycompany/myproject/domain/system/maps
                </value>
            </list>
        </property>
    </bean>
    
    <!-- DAO -->
    <bean id="userDAO" parent="baseDAO"
        class="com.mycompany.myproject.module.system.dao.UserDAOImpl">
        <constructor-arg>
            <value>com.mycompany.myproject.domain.system.User</value>
        </constructor-arg>
    </bean>

    <!-- Service -->
    <bean id="userService" parent="baseTransactionProxy">
        <property name="target">
            <bean
                class="com.mycompany.myproject.module.system.service.UserServiceImpl">
                <property name="userDAO" ref="userDAO" />
            </bean>
        </property>
    </bean>

이 파일 에 서 는 parentSession Factory 를 계승 하 는 session Factory 를 설명 합 니 다.mappingDirectory Locations 만 설정 하면 됩 니 다.
AbstractSystemTest.java

public abstract class AbstractSystemTest extends
        AbstractTransactionalDataSourceSpringContextTests ...{

    protected String[] getConfigLocations() ...{
        String[] config = new String[] ...{ "testApplicationContext.xml",
                "system/testSystemContext.xml" };
        return config;
    }

}

기본 클래스 를 덮어 쓰 는 방법 은 설정 파일 을 찾 는 기능 을 제공 합 니 다.상황 에 따라 기본 클래스 를 AbstractTransactionalSpringContextTests 로 변경 할 수 있 습 니 다.
UserDAOImplTest.java

public class UserDAOImplTest extends AbstractSystemTest ...{

    public UserDAO getUserDAO() ...{
        return (UserDAO) applicationContext.getBean("userDAO");
    }

    public void testLoadObject() ...{
        User user = (User) this.getUserDAO().find("01");

        assertNull(user);
    }
}

UserServiceImplTest.java

public class UserServiceImplTest extends AbstractSystemTest ...{

    public UserService getUserService() ...{
        return (UserService) applicationContext.getBean("userService");
    }

    public void testLoadUser() ...{
        User user = (User) this.getUserService().find("01");

        assertNull(user);
    }
}

나의 기본 전략 은 모든 개발 자가 쓴 단원 테스트 간 에 서로 간섭 하지 않도록 하 는 것 이다.사실은 spring 의 관건 적 인 문제 에 있어 context 설정 파일 을 불 러 오 는 것 이 서로 간섭 하지 않 는 다.위의 예제 에 따 르 면,spring 이 제공 하 는 프로필 을 사용 하면 이 목적 을 쉽게 달성 할 수 있 음 을 나타 낸다.
그러나 프로젝트 중후 반 이 되면 service 가 자신의 모듈 에 속 하지 않 는 DAO 에 자주 접근 하거나 domain 대상 의 관련 이 hibenate 설정 파일 에 매 핑 되 는 것 을 발견 할 수 있 습 니 다.이 방식 은 시간 이 많이 걸 립 니 다.다른 모듈 의 배치 파일 을 가 져 와 야 하기 때문에 session Facotry 설정 을 사용 할 수 있 습 니 다.그리고 이때 domain 대상 도 안정 되 어 자주 나타 나 지 않 습 니 다.
unmmaped class 의 이상.
글 한 편 을 쓰 는 것 은 정말 고 통 스 럽 습 니 다.5 시간 을 했 는데 정말 시간 이 걸 렸 습 니 다.

좋은 웹페이지 즐겨찾기