IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  자바 | 웹 개발  >

스프링 2와 JPA 시작하기 (한글)

이클립스와 DB2 Express-C를 사용해 스프링 2 프레임워크와 Java Persistence API 알아보기

developerWorks
Go to the previous page16 페이지 중 6 페이지Go to the next page

문서 옵션

샘플 코드


제안 및 의견
피드백

튜토리얼 평가

이 컨텐츠를 개선하기 위한 도움을 주십시오.


RDBMS로 수행하는 DAO 통합 테스트 작성하기

이번 절에서는 데이터베이스에 대한 직원 정보 시스템을 테스트하기 위해 통합 테스트를 작성하고 실행해볼 것이다.

EmployeeService의 구현체인 EmployeeDAO 테스트하기

이제 다음 질문만 남았다. 언제 어떻게 스프링 2 엔진이 호출되고, dwspring2-service.xml 설정 파일을 사용해야 하는지를 어떻게 알 수 있는가?

답은 EmployeeServiceIntegrationTest.java에 있는 통합 테스트를 수행하는 소스 코드를 보면 정확하게 알 수 있다. 이 통합 테스트는 실제 RDBMS에 대해 EmployeeService를 구현한 EmployeeDAO를 테스트할 것이다. 이제 코드 일부분을 살펴보자(Listing 12).


Listing 12. EmployeeServiceIntegrationTest 통합 테스트 코드(파트 1)
                    
package com.ibm.dw.spring2;

import java.util.Date;
...

import org.springframework.test.jpa.AbstractJpaTests;

public class EmployeeServiceIntegrationTest extends AbstractJpaTests {

   private EmployeeService employeeService;

   private long JoeSmithId = 99999;

   public void setEmployeeService(EmployeeService employeeService) {
      this.employeeService = employeeService;
   }

   protected String[] getConfigLocations() {
                      return new String[] { "classpath:/com/ibm/dw/spring2/dwspring2-service.xml" };
                     }
                

통합 테스트에서 이 부분은 스프링 2 라이브러리에 있는 AbstractJpaTests 클래스를 상속 받아 작성했다. Listing 12에서 굵게 표시한 getConfigLocations() 메서드를 구현함으로써, 스프링 2 엔진에 의해 분석될 수 있는 하나 이상의 빈 설정 파일을 제공할 수 있다. 백 엔드(back-end)와 사용자 인터페이스 빈 설정 파일을 분리하는 것이 실제 적용에서 일반적이기 때문에, 여러 개의 설정 파일을 갖고 있을 수도 있다.

Listing 12의 setEmployeeService() 메서드는 의존성 주입의 좋은 예이다. 스프링 2 엔진이 EmployeeServiceIntegrationTest 클래스를 로드할 때(AbstractJpaTests를 상속한) 충족되지 않은 의존성, 즉 EmployeeService 타입의 속성을 발견한다. 스프링 2 엔진은 EmployeeService 타입으로 설정된 빈이 있는지 dwspring2-service.xml에서 찾은 다음 setEmployeeService() 메서드를 통해 의존성을 주입한다.




위로


타입으로 자동 묶기

dwspring2-service.xml 파일에서 employeeService 주입을 위한 명시적인 묶기 참조 정보가 부족한 것을 알 수 있을 것이다. 사실 이 주입은 자동으로 이뤄진다. 이것을 스프링 용어로 autowiring이라 부른다.

AbstractJpaTests 기본 클래스는 AbstractDependencyInjectionSpringContextTests 클래스를 상속한다. AbstractDependencyInjectionSpringContextTests는 기본으로 스프링의 타입에 의한 autowire 설정에 의해 간단하게 테스트를 할 수 있게 해준다. 이 클래스의 하위 클래스에 있는 모든 의존성(public 속성)-EmployeeServiceIntegrationTest와 같은 하위 클래스-은 애플리케이션 문맥(이 경우 dwspring2-service.xml 파일에 의해 구성된)에 같은 유형의 빈이 있는 경우 자동으로 주입된다.




위로


통합 테스트 준비

테스트를 위한 AbstractJpaTests의 유용한 특징은 트랜잭션으로 테스트를 수행하고, 테스트가 끝난 후에는 테스트를 통해 발생한 모든 영향을 롤백하는 기능이다. 이것은 실행한 각 테스트 사이에서 생긴 데이터를 삭제하고 다시 생성하는 작업이 필요 없기 때문에 테스트 속도를 상당히 빠르게 해준다.

Listing 13은 각 테스트를 위한 최초 준비 작업을 수행하는 코드를 보여준다. 이 코드는 Employees와 관련 Addresses 정보를 데이터베이스에 반영하는 코드다. 그렇지 않으면 트랜잭션은 항상 롤백되기 때문에, 추가되는 데이터를 보지 못할 것이다. 같은 트랜잭션 내에서 셋업 메서드를 실행하기 위해서는 Listing 13에 나오는 onSetUpInTransaction() 메서드를 재정의(override)하면 된다.


Listing 13. EmployeeServiceIntegrationTest 통합 테스트 코드(Part 2)
                    
protected void onSetUpInTransaction() throws Exception {
      Employee emp1 = new Employee("0001", "Joe", "R","Smith", 
             "4853", "Engineer", 3, 'M',
              20000.00, 0.00, 0.00,
               new Address(10, "Walker Street")
              , new Date(), new Date());
      Employee emp2 = new Employee("0002", "John","T","Lockheed", 
            "4333", "Sales", 2, 'M',
            40000.00, 0.00, 5000.00,
            new Address(20, "Walker Street")
            , new Date(), new Date());
      Employee emp3 = new Employee("0003", "Mary","M","Johnson", 
            "4383", "Admin", 3, 'F',
            60000.00, 0.00, 390.00,
            new Address(123, "Booth Ave")
            , new Date(), new Date());
            
      employeeService.save(emp1);
      employeeService.save(emp2);
      employeeService.save(emp3);

      JoeSmithId = emp1.getEmpid();
   }

Employee 인스턴스를 생성하고 JPA 기반의 employeeService를 통해 영속화되는 것이 얼마나 직관적인지 주목하라. save() 메서드는 JPA의 persist() 오퍼레이션을 호출하고, 이 오퍼레이션은 Employee에서 Address 객체로 연속해 영향을 미치며(Employee POJO의 JPA 어노테이션으로 지정했다), 더 나아가 address 테이블에 새로운 기록을 생성하는 것도 JPA로 생성할 수 있다.

onSetUpInTransaction(의 셋업 코드는 각각의 모든 테스트 케이스마다 수행된다. 이렇게 하면 각 테스트 수행 이전에 세 개의 employee 정보가 영속화된다는 것을 보장할 수 있다.

테스트의 예제로 Listing 14는 EmployeeDAOupdate() 메서드를 위한 테스트 메서드인 testModifyEmployee()를 보여준다.


Listing 14. EmployeeServiceIntegrationTest 통합 테스트 코드(Part 3)
                    
public void testModifyEmployee() {
      String oldLastName = "Lockheed";
      String newLastName = "Williams";
      Employee emp = employeeService
            .findByEmployeeLastName(oldLastName).get(0);
      emp.setLastName(newLastName);
      
      Employee emp2 = employeeService.update(emp);
      assertEquals(newLastName, emp2.getLastName());

      List<Employee> results = employeeService
            .findByEmployeeLastName(oldLastName);
      assertEquals(0, results.size());

      results = results = employeeService
            .findByEmployeeLastName(newLastName);
      assertEquals(1, results.size());

   }

Listing 14의 testModifyEmployee() 테스트 케이스는 EmployeeServiceupdate() 메서드를 사용해 "John Lockheed" 의 성(姓)을 "Lockheed"에서 "Williams"로 변경한다. 그 다음으로 findByEmployeeLastName("Williams")를 호출함으로써 성이 "Williams"인 직원이 있는지 확인한다. 또한 성이 "Lockheed"인 직원이 없는지 확인한다.

EmployeeServiceIntegrationTest에는 여러 가지 기타 테스트가 있다. 이 테스트들을 공부하면 실제 데이터를 조작하기 위해 EmployeeService 구현에 있는 메서드를 어떻게 사용할 수 있는지 알 수 있을 것이다(다운로드 참조).

다음으로 RDBMS에 대해 통합 테스트를 실행하기 위한 환경을 구축해 보자.




위로


JPA 레퍼런스 구현 다운로드와 설치

JPA는 EJB 3.0 명세의 일부분이며, EJB 3.0은 자바 EE 5 명세의 핵심 컴포넌트다. 그렇기 때문에 JPA의 오픈 소스 레퍼런스 구현은 GlassFish 자바 EE 5 레퍼런스 서버의 일부분이 된다.

아직 JPA 구현체를 받지 못했다면, 통합 테스트를 위해 지금 JPA 구현체를 다운로드하고 설치해야 한다.

클래스패스 준비하기

애플리케이션에서 JPA에 접근하기 위해서는, 실행시에 참조하는 클래스패스에 JPA 레퍼런스 구현 JAR가 있어야 한다.

  1. 이클립스에서는 Navigator 화면의 프로젝트 이름에서 오른쪽 클릭을 하고 Properties를 선택한다.
  2. Java Build Path를 선택하고, 대화창에서 Libraries 탭을 선택한다.
  3. Add External JARs 버튼을 클릭하고, JPA를 다운로드한 것 중 toplink-essentials.jar 파일을 포함시키고 확인을 누른다.

통합 테스트가 성공적으로 컴파일되고 실행되기 위해서는 빌드 패스와 런타임 패스 안에 의존하는 모든 라이브러리가 있어야만 한다. 표 3은 빌드와 런타임 클래스패스에 갖고 있어야 하는 JAR 파일을 보여준다. 이클립스에서 이 패스들을 설정할 수 있다.


표 3. 클래스패스에 있어야만 하는 오픈 소스 라이브러리
JAR 파일다운로드할 수 있는 곳
commons-logging.jarspring-framework-2.x-with-dependencies.zip
db2jcc.jarIBM DB 2 Express-C 배포판
db2jcc_licence_cu.jarIBM DB2 Express-C 배포판
hsqldb.jarspring-framework-2.x-with-dependencies.zip
junit.jarspring-framework-2.x-with-dependencies.zip
log4j-1.x.xx.jarspring-framework-2.x-with-dependencies.zip
persistence.jarspring-framework-2.x-with-dependencies.zip
spring.jarspring-framework-2.x-with-dependencies.zip
spring-core.jarspring-framework-2.x-with-dependencies.zip
spring-jpa.jarspring-framework-2.x-with-dependencies.zip
spring-mock.jarspring-framework-2.x-with-dependencies.zip
toplink-essential.jarJPA 참조 구현 다운로드



위로


persistence.xml 파일 포함하기

persistence.xml 파일은 JPA 통합 시나리오에서 설정 정보를 제공하지는 않지만, JPA 명세에 의해 필요하다.

persistence.xml 파일은 영속성 단위(persistence unit)를 설명한 것이다. JPA 용어로 영속성 단위는 EntityManagerFactory(그리고 관련 설정 정보)와 더불어, EntityManagerFactory 가 만드는 EntityManagers 그리고 EntityManagers가 관리하는 클래스들을 포함한다(그리고 어노테이션이나 XML 형태의 이 클래스들을 위한 JPA 메타데이터).

이 경우 persistence.xml 파일은 Listing 15에서 볼 수 있는 것처럼 매우 단순하다.


Listing 15 META-INF/persistence.xml 파일
                    
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="dwSpring2Jpa" transaction-type="RESOURCE_LOCAL"/>
</persistence>

특정 벤더의 설정에서는 persistence.xml 파일에 설명에 관련된 정보가 들어있을 수도 있지만, 스프링/JPA 통합을 위한 정보는 없다. 단지 META-INF/persistence.xml에 파일이 복사되어 있는지 확인할 필요가 있다.




위로


스프링 통합 테스트 수행하기

빌드 패스가 구성되었으므로 이제 통합 테스트를 수행할 수 있다.

이클립스에서 통합 테스트를 수행하기 위해서는 Navigator 화면에서 EmployeeServiceIntegrationTest.java 파일을 선택하고, 오른쪽 클릭을 하고, Run As -> JUnit Test를 선택한다. 이렇게 하면 통합 테스트가 시작된다. 이 테스트는 인 메모리 데이터베이스에 대해 수행돼 매우 빠르다는 점을 기억해야 한다. 실행되는 동안 이클립스 콘솔 창에 테이블 생성, SQL 삽입, 질의에 대한 메시지가 기록되는 것을 볼 수 있다. 통합 테스트를 수행한 예제는 그림 7에서 볼 수 있다.


그림 7. 이클립스에서 통합 테스트 수행하기




위로


인 메모리 데이터베이스에서 DB2 Express-C로 데이터베이스 변경하기

일반적으로 스프링 DAO와 DAO 디자인 패턴을 사용한다면, 데이터 소스는 완벽하게 캡슐화되어 있고, 애플리케이션 코드에서 이를 숨겨준다. 사실상 예제에 나와 있는 코드는 완벽하게 사용하는 관계형 데이터베이스에서 독립적으로 되어 있고, 그뿐만 아니라 특정 JPA 벤더에서도 독립적이다. 이런 유연성 덕분에 같은 애플리케이션 코드를 실행이 빠른(인 메모리 데이터베이스와 같은) 데이터베이스에서 테스트를 하고, 그리고 나서 실제로는 견고하고, 확장성 있는 상용 데이터베이스(IBM DB2 Express-C와 같은)에서 배치할 수 있는 것이다.

다른 데이터베이스로 교체하기 위해서는 단지 dwspring2-service.xml 빈 기술서 파일을 수정만 하면 된다. Listing 16에서는 HSQLDB에서 DB2 Express-C로 데이터 소스를 변경하는 데 필요한 변경 내용(굵게 표시함)을 보여준다.


Listing 16. DB2 Express-C로 데이터 소스 변경하기
                    
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="employeeService" class="com.ibm.dw.spring2.EmployeeDAO">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
   </bean>
   
   <bean id="entityManagerFactory" class=
      "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
      <property name="dataSource" ref="dataSource"/>
      <property name="jpaVendorAdapter">
         <bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
            <property name="showSql" value="true"/>
            <property name="generateDdl" value="true"/>
            <property name="databasePlatform" 
                    value="oracle.toplink.essentials.platform.database.DB2Platform"/>
         </bean>
      </property>
      <property name="loadTimeWeaver">
         <bean class="org.springframework.instrument.classloading.SimpleLoadTimeWeaver"/>
      </property>
   </bean>
   
   <bean id="dataSource" class=
      "org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
                    <property name="url" value="jdbc:db2://192.168.23.36:50000/dwspring"/>
                    <property name="username" value="bill" />
                    <property name="password" value="lotus123" />
      
   </bean>

   <bean id="transactionManager" class=
      "org.springframework.orm.jpa.JpaTransactionManager">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
      <property name="dataSource" ref="dataSource"/>
   </bean>

</beans>

Listing 16에서 강조한 수정 부분은 192.168.23.36의 50000(기본) 포트에 DB2 Express-C의 인스턴스가 있다고 가정한다. dwspring라는 데이터베이스를 생성해야 하고 애플리케이션 사용자(Listing 16에는 bill로 되어 있지만, 특정 사용자로 변경할 수 있음)가 완벽하게 접근할 수 있는 권한을 제공해야 한다.

이제 다시 통합 테스트를 실행하자. 테스트는 DB2 Express-C 데이터베이스에 접속하고, 테이블을 생성하고, 모든 테스트를 수행한다. 이전보다 속도는 조금 늦어진 것-이제 테스트는 네트워크를 통해 수행되고, 온 디스크(on-disk) 데이터 저장소를 사용하기 때문이다-을 제외하고는 실행에 있어서는 변한 것은 거의 없음을 알 수 있을 것이다. 그림 8은 이클립스에서 DB2 Express-C를 통한 전형적인 실행을 보여준다.


그림 8. DB2 Express-C에 대해 통합 테스트 수행하기

애플리케이션을 위한 데이터 티어는 이제 완벽하게 수행되고, 테스트되었다. 데이터 티어는 다양한 사용자 인터페이스에서 사용될 수 있다. 예를 들어, 이것을 명령행 인터페이스 레이어로 나눌 수도 있고, GUI 팻 클라이언트로 만들길 원할 수도 있다. UI와 데이터 접근 티어의 디커플링(decoupling)은 독립적으로 테스트된 데이터 티어 코드에 쉽게 적용하고, 용도를 변경할 수 있기 때문에 중요하다.

이번 실습에서는 애플리케이션용 웹 기반 UI를 만들기 위해 스프링 MVC를 사용할 것이다.




위로



Go to the previous page16 페이지 중 6 페이지Go to the next page
    IBM 소개 개인정보 보호정책 문의