'테스트@'에 해당되는 글 17

  1. 2010.12.20 Short-circuit 확인 테스트 코드
  2. 2010.11.14 테스트 시작하기, 좋은 시작~
  3. 2010.11.11 왜 소스를 보지 못하나.
  4. 2010.10.22 외부 시스템과의 연동 테스트시 로컬에서 진행하기???
  5. 2010.09.05 Spring JNDI Mock
  6. 2010.07.14 Mapping of MIME Types
  7. 2010.06.21 에러 잡기의 단계
  8. 2010.05.25 이상한 논리 로직
  9. 2010.05.23 PropertyFromFileTest
  10. 2010.05.23 FilePathTest
  11. 2010.04.13 JUnit4
  12. 2010.03.29 Call By Reference Vs Call By Value
  13. 2010.01.10 Developing a Spring Framework MVC application step-by-step 테스트케이스
  14. 2010.01.09 [해석] Developing a Spring Framework MVC application step-by-step Chapter 1. Basic Application and Environment Setup
  15. 2009.09.22 테스트 코드 작성을 위한 Workshop
  16. 2009.08.08 Spring 2 + JPA + Tomcat
  17. 2009.03.01 유지보수 - 소스

Short-circuit 확인 테스트 코드


테스트 시작하기, 좋은 시작~

H가 우리 팀으로 합류했다.
계속 테스트에 대한 이야기를 했더니 이번 수정사항에 대해서 테스트 코드를 짜왔다.
오호...

- 기존 소스

1. 별도의 main 메서드를 이용했다.
그래, 방법이 중요한게 아니야.

2. 테스트를 해야 하는 부분이 해당 업무의 끝부분이다.
데이터베이스 접근도 많이 하고 각종 설정이 필요하다.
그래서 테스트하려고 하는 부분의 소스 코드 조각을 따로 떼어서 테스트 코드에 복사했다.
필요한 부분만 복사해서 테스트한거는 나름대로 고민한 끝에 나온 방법이네.
그런데 복사한 소스는 중복이 되고, 나중에 업무 로직이 변경되어서 소스가 변경되었는데 테스트 코드는 변경되지 않을 수도 있잖아.

3. 테스트하려는 코드내에서 데이터베이스를 접근하는 코드가 있다.
데이터베이스를 접근하는 코드는 위와 같이 해서 제거했는데 이 부분은 뺄 수가 없다.
그래서 별도의 메서드로 만들어서 테스트 데이터를 리턴하게 만들었다.
좋은 시도다.
ERPDAO가 외부에서 변경이 가능했다면 더 좋았을텐데.
아니면 이 부분도 별도의 메서드로 빼서 구현해 놓으면 교체가 쉬울텐데.
ERPDAO처럼 우리가 데이터를 마음대로 변경할 수 없는 경우 테스트하기가 곤란하다.
지금 테스트를 통과하는 데이터가 내일은 없을지도 모른다.
이런 곳은 Mock이 좋겠다. 아니면 동의어를 사용해서 로컬에 테이블을 만든다.

- H가 작성한 테스트 코드
- 좀 더 개선한다면

왜 소스를 보지 못하나.

SOAP을 통해서 데이터를 주고 받는 시스템
데이터가 조금 많기는 하지만 내부 업무 로직이 더 복잡하다.
금액을 계산하고 과거 데이터를 조회하고.
나는 서버측과 클라이언트측 중간에서 데이터를 전달하는 모듈을 맡고 있다.

이 시스템을 유지보수하는 인력들의 기술력은 그다지 높지 않다.
업무를 잘 알기는 하지만 자바 기초 문법 정도만 알고 있다.

이런 상황에서 서버측 문제가 발생하면 해결을 하지 못한다.
담당자들이 소스를 아무리 들여다보고 있어도 추측만 할 뿐이지 명확하게 이야기하지 못한다.
SOAP 메세지를 파싱하고 복호화를 해서 데이터(XML)를 가져와서 내부 업무 로직을 태우는데 자바에 익숙지 않아서 무리가 따른다.

덩치 큰 업무 시스템이어서 로컬에서 돌리기에도 힘들고 - 이것저것 세팅을 해야 하고, IP도 변경해야 하고
서버에서 돌아가는 로그만 보고 있으니 디버깅하기가 참 힘들겠다는 생각이 든다.

그런데 이 프로그램을 로컬에서 간단하게 돌릴수 있으면, 콘솔에 변수를 찍어가며 데이터를 확인해 보면서 디버깅을 할 수 있지 않을까하는 생각이 든다.
자바에 익숙하지 않아도 눈으로 보면서 해보면 업무를 아니깐.

그래! 테스트를 작성하자!
로컬에서 언제든지 동작하는 테스트케이스를 작성해 두면 담당자들이 디버깅하기도 쉽고, 소스를 안보려고 회피하는 모습을 더이상 안봐도 된다.

- 클라이언트측에서 전송한 데이터를 처리하는 부분은 XML 데이터를 입력받을 수 있게 하고
- 데이터베이스 연결은 WAS에 종속적이지 않게 하고
- 에러가 발생하는 부분의 클래스만 생성해서 돌려보면 된다.

외부 시스템과의 연동 테스트시 로컬에서 진행하기???

상대방의 서버에서 SOAP 메세지를 보내오면 첨부된 XML 파일을 읽어서 데이터를 처리하는 기능이 있다.
이 XML 파일을 처리하면서 어떤 오류가 발생했다.

이 오류를 확인하기 위해서는 상대방에게 계속 동일 데이터를 매번 요청해야 한다.
이게 의심이 나면 수정하고 WAS 내렸다 올리고 전화해서 데이터 보내달라고 하고, 몇 분 기다렸다 데이터 보내주면 다시 디버깅하고.
상대방이 데이터를 바로 보내주면 다행이다.
그 사람들도 본업이 있는지라 1시간 뒤에 보내줄때도 있고, 가끔 시스템 장애로 다음 날 보내주는 경우도 있다.

SOAP 메세지는 문제없으니깐 XML 처리하는 부분만 테스트하자.
로그에서 첨부된 XML을 가져와서 이 부분만 테스트하자. - 데이터를 다시 보내달라고 할 필요없음.
- WAS 재기동 필요없음.
- 여기까지만 하다보니 문제점이 보였다.

우캬캬.

Spring JNDI Mock

일반적인 웹어플리케이션은 WAS에서 JNDI를 통해서 데이터베이스 커넥션을 가져온다.
이런 방법이 편한듯 하면서도 형상관리 서버에서 소스를 가져올 때 매번 WAS 설정을 해야 해서 귀찮았다.

테스트 코드에 관심을 가지면서 가장 문제된 부분이 데이터베이스 커넥션인데 WAS를 기동하지 않은 상태에서 JNDI를 가져오는게 쉽지 않았다.
별별 이상한 방법(?, 고민[각주:1], 방법1[각주:2], 방법2[각주:3])을 사용해서 소스를 리팩토링했는데 스프링 Mock에 포함된 SimpleNamingContextBuilder 를 알고 나서 반나절동안 패닉 상태에 빠졌다.

그냥 이 코드 한줄이면 JNDI를 WAS에 종속적이지 않게 lookup 할 수 있었다.

- 오늘의 교훈
역시 사람은 배워야 한다.
모르면 손발이 고생한다.
  1. 복잡한 기존 소스를 테스트 가능하게 리팩토링하기 [본문으로]
  2. 테스트 가능한 Connection 을 사용하도록 리팩토링하기 [본문으로]
  3. 테스트 어려움 - 싱글톤 클래스 [본문으로]

Mapping of MIME Types

MimeBodyPart.getContent() 의 리턴되는 객체가 String이였는데 JEUS 6에서는 에러가 발생한다.
java.lang.ClassCastException: javax.xml.transform.stream.StreamSource incompatible with java.lang.String

소스가 (String)MimeBodyPart.getContent() 이렇게 되어 있다.
확인 결과 JEUS의 라이브러리인 javaee.jar에서 발생하였고 기술지원을 받음.
getContent()는 MIME 타입에 따라 다른 객체를 리턴한다고 한다.

Tmax의 답변
기존 J2EE 1.4에서는 엄격하게 적용하지 않았지만, JavaEE 5 부터 JAX-WS 가 도입되면서 부터는
매핑을 엄격하게 적용하여 구현하고 있습니다.

 MIME Type  Java Type
 image/gif  java.awt.Image
 image/jpeg
 java.awt.Image
 text/plain
 java.lang.String
 multipart/*
 javax.mail.internet.MimeMultipart
 text/xml or application/xml
 javax.xml.transform.Source

MIME 타입이 xml 이므로 거기에 해당하는 객체가 리턴되고 적절한 처리를 하면 된다.

 
- 테스트케이스
- MIME 타입에 따른 처리가 되는지 확인하기 위해 javax.activation.debug 시스템 프로퍼티를 true로 하면 자세한 로그 내용을 볼 수 있다.



에러 잡기의 단계

1. 말 그대로 디버깅을 한다.
디버깅 툴이나 IDE에서 제공하는 디버깅 기능을 이용해서 디버깅을 한다.
처음에는 신기해 한다.
그러나...원격에서 운영되고 있는 서버를 디버깅 모드로 돌릴 수는 없잖아.

2. 철두철미하게 로깅을 한다.
로그를 잘 남기면 에러 잡는 거는 시간 문제다.
로그 파일이 엄청나게 쌓인다. ㅎㅎ
로그는 정확하게 영리하게 남겨야 한다.

3. 테스트 케이스를 작성한다.
테스트 케이스를 통해서 에러가 발생할 곳을 미리 찾아 낸다.
운영중에 에러가 발생하더라도 테스트 케이스를 실행해서 힌트를 얻는다.
진정한 고수의 수준이 아닌가 싶다.

- 기본적으로는 에러 체크/예외 처리를 잘하고 방어적인 코딩을 해야겠지

이상한 논리 로직

- 테스트 통과- 반대로 해도 테스트 통과- 이상한 로직, 테스트 실패- 반대로 해도 테스트 실패이 경우는 말이 안된다. null 이면서 "" 일 수는 없다.

논리 로직이 복잡할 때는 반대로 뒤집어서 생각해 본다.
이상한 로직을 처음 봤을 때, &&를 ||로 잘못 넣은 것인줄 알았다.

PropertyFromFileTest

- message.properties
key = value
key.endWithSpace = value.endWithSpace //공백을 넣어 둔다.
key.endWithTab = value.endWithTab    //Tab을 넣어 둔다.

FilePathTest

JUnit4

JUnit 4로 뛰어들기
Andrew Glover

기존 버전과 차이점을 비교해서 잘 보여주고 있어서 기존 JUnit 사용법도 배울수 있다.

- 기존 버전의 문제
테스트 메서드는 test라는 단어로 시작해야 한다.
테스트를 포함하는 클래스는 TestCase를 상속받아야 한다.

JUnit4
- JUnit 4에서는 테스트 메서드에 @Test 를 추가한다.
- import static 을 이용해서 org.junit.Assert.assert* 메서드를 사용한다.

- 예외 테스트
예전 버전 JUnit4 - TestSuite - 전/후처리
setUpBeforeClass
setUp
method1
tearDown
setUp
method2
tearDown
tearDownAfterClass

- 매개변수 테스트
1. 매개변수를 사용하지 않는 일반 테스트를 작성한다. 2. Collection 유형을 반환하는 static 피더 메서드를 작성하고 @Parameters 주석으로 표시한다. 3. 첫 번째 단계에서 정의한 일반 메서드에 필요한 매개변수 유형에 대한 클래스 멤버를 만든다. 4. 이러한 매개변수 유형을 사용하고 이를 세 번째 단계에서 정의한 클래스 멤버와 연결하는 생성자를 만든다. 5. @RunWith 주석을 통해 Parameterized 클래스와 함께 실행할 테스트 케이스를 지정한다. 테스트를 실행하면 verifyGoodZipCode() 테스트 메서드가 regExValues() 데이터 피더 메서드에 정의된 각 값에 대해 한번씩 네번 실행된다.

- timeout, @Ignore, 명령행에서 실행, ant에서 사용, 배열을 검사하는 assertEquals() 추가

Call By Reference Vs Call By Value

한번씩 까먹는다.
정말 기초가 중요하다.

- Call By Reference Vs Call By Value
- 테스트 작성[각주:1]
  1. 2011-02-10 추가 [본문으로]

Developing a Spring Framework MVC application step-by-step 테스트케이스

- Chapter 1
처음에는 단순히 리턴하는 모델의 뷰이름만 확인한다.

- Chapter 2.2
모델의 뷰이름이 제대로 되었는지 확인하고 모델 데이터가 있는지 확인한다.
- Chapter 2.3

- Chapter 3.2
도메인객체에 대한 테스트

서비스 클래스에 대한 테스트

[해석] Developing a Spring Framework MVC application step-by-step Chapter 1. Basic Application and Environment Setup

http://web.archive.org/web/20161119155731/http://docs.spring.io/docs/Spring-MVC-step-by-step/part1.html

Chapter 1. Basic Application and Environment Setup.pdf


1장. 기본 어플리케이션 및 환경설정

1.1. 프로젝트 디렉토리 생성

모든 소스와 작성할 파일을 저장할 디렉토리를 springapp/라고 하자.
자바소스를 저장할 src/를 만든다.
어플리케이션을 패키징하고 배포할 WAR에 들어갈 모든 파일을 저장할 war/를 만든다.
war/에는 자바소스를 제외한 JSP 소스, 설정파일이 저장된다.

1.2. index.jsp 작성하기

아주 간단한 index.jsp를 war/에 작성하자.
index.jsp는 우리가 만드는 어플리케이션의 시작점이 된다.
'springapp/war/index.jsp': war/에 WEB-INF/를 만들고 WEB-INF/ 아래에 web.xml을 만든다.
'springapp/war/WEB-INF/web.xml':
1.3. Tomcat에 배포하기

이 Tutorial에서 계속 사용될 Ant 빌드 스크립트를 만들자.
이 빌드 스크립트에는 컴파일, 빌딩, 배포하는 타겟이 있고, 일부는 특정 서버에만 사용되는 것도 있다.
'springapp/build.xml': Tomcat이 아닌 다른 WAS를 사용한다면 빌드 스크립트 마지막 부분은 지워도 된다.
WAS의 hot deploy 특성에 따르거나, 직접 서버를 내렸다 올려야 한다.

IDE를 사용한다면 build.xml의 Tomcat 타겟에 에러 표시가 보일지도 모르는데 무시해도 된다.

Ant 빌드 스크립트가 개발을 좀더 쉽게 할 수 있게 도와 줄것이다.
여기에 사용된 대부분의 내용은 Ant나 Tomcat의 기본적인 내용이므로 자세한 설명은 생략한다.
빌드 파일 내용을 springapp/에 build.xml에 넣기만 하면 된다.
그리고 같은 위치에 build.properties를 만들고 서버가 설치된 위치를 맞춘다.
'springapp/build.properties':
# Ant properties for building the springapp

appserver.home=${user.home}/apache-tomcat-6.0.14
# for Tomcat 5 use $appserver.home}/server/lib
# for Tomcat 6 use $appserver.home}/lib
appserver.lib=${appserver.home}/lib

deploy.path=${appserver.home}/webapps

tomcat.manager.url=http://localhost:8080/manager
tomcat.manager.username=tomcat
tomcat.manager.password=s3cret

당신이 시스템에 Tomcat을 설치하지 않았다면 Tomcat 소유주가 appserver.home/webapps/에 대해 모든 권한을 줘야 한다.
또는 소유주가 appserver.home/webapps/springapp/를 만들고 이 디렉토리에 모든 권한을 줘야 한다.
리눅스에서는 chmod a+rwx springapp 라는 명령어를 사용하면 모든 사용자에게 모든 권한을 줄수 있다.

'appserver.home/conf/tomcat-users.xml'에 사용자를 추가한다. 이제 모든 준비가 다 되었고 springapp/에서 ant 명령을 실행시킨다.
빌드하거나 배포하려면 deploy나 deploywar 타겟을 실행시킨다.

1.4. 어플리케이션 확인

${appserver.home}/bin/startup.bat 을 실행시켜서 Tomcat을 시작하자.
Tomcat이 우리가 만든 어플리케이션을 올렸는지 list 태스크로 확인할 수 있다.

브라우저로 http://localhost:8080/springapp/index.jsp을 열어보자.

1.5. Spring 프레임워크 다운로드

Spring Framework 2.5를 다운로드 받고 적당한 곳에 압축을 푼다.

1.6. web.xml 수정

springapp/war/WEB-INF/web.xml을 수정한다.
Front Controller인 DispatcherServlet을 설정한다.
나중에 설정할 정보에 기반하여 보내질 모든 요청을 처리한다.
이 서블릿 정의는 servlet-mapping 엔트리로 여기서 사용될 URL 패턴을 매핑한다.
우리는 htm 확장자를 가진 모든 URL을 springapp 서블릿으로 보내도록 설정한다.
'springapp/war/WEB-INF/web.xml':

springapp-servlet.xml을 springapp/war/WEB-INF/에 만든다.
이 파일은 DispatcherServlet에서 사용되는 빈에 대한 정의를 한다.
모든 웹 관련 컴포넌트가 사용할 WebApplicationContext이다. =-=> ???
이 파일의 이름은 web.xml 의 servlet-name 엘리먼트에 -servlet을 붙여서 만든다.
이것은 Spring Web MVC 프레임워크의 표준 명명법이다.
이제 /hello.htm 에 대한 빈을 설정하고 class는 springapp.web.HelloController로 하자.
이것은 /hello.htm 이라는 URL에 대한 요청을 controller가 처리하게 한다.
Spring Web MVC 프레임워크는 요청 URL과 처리할 객체를 매핑하는데 HandlerMapping 인터페이스 구현체를 사용한다.
DispatcherServlet과 달리 HelloController는 특정 페이지에 대한 요청을 처리한다.(Fowler는 이것을 Page Controller라고 한다.)
DispatcherServlet이 사용하는 기본적인 HandlerMapping은 BeanNameUrlHandlerMapping이다.
이 클래스는 빈이름을 요청의 URL과 매핑해서 DispatcherServlet이 어떤 컨트롤러를 호출할지 알려준다.
'springapp/war/WEB-INF/springapp-servlet.xml':

1.7. WEB-INF/lib에 라이브러리 복사하기

war/WEB-INF/lib/를 만들고 Spring 배포본에서 spring.jar, spring-webmvc.jar, commons-logging.jar를 복사해 넣는다.
이 라이브러리는 서버에 배포되고 빌드에 사용된다.

1.8. Controller 만들기

springapp.web 패키지에 HelloController를 만든다.
src/springapp/web/에 HelloController.java를 만든다.
'springapp/src/springapp/web/HelloController.java':

이것은 아주 기본적인 Controller 구현이다.
우리는 나중에 Spring에서 제공하는 Controller 구현체를 구현해서 확장할 것이다.
Spring Web MVC에서 Controller는 요청을 처리하고 ModelAndView를 리턴한다.
이 경우에는 hello.jsp이다.
이렇게 리턴한 모델은 ViewResolver에 의해서 수행된다.
우리는 명시적으로 ViewResolver를 지정하지 않았기 때문에 Spring에 기본적으로 제공된다.(view 이름에 해당하는 URL로 포워딩한다.)
이 핸들러로 실제로 요청이 왔는지 로거를 찍어본다.
Tomcat을 사용하면 로그가 appserver.home/log/catalina.out에 출력된다.

IDE를 사용하면 lib/의 jar파일을 빌드 패스에 추가해야 한다.
서블릿 컨테이너의 servlet-api.jar도 추가해야 HelloController.java가 제대로 컴파일된다.

1.9. Controller에 테스트 작성하기

테스트는 소프트웨어 개발에 있어서 필수적이다.
애자일 개발에 있어서도 핵심 practice이다.
controller에 복잡한 로직을 넣기 전에 테스트를 작성한다.
테스트는 개발이 진행됨에 따라 변경에 대한 신뢰를 줄수 있다.
springapp/ 아래에 test/를 만들어서 테스트를 작성한다.

HelloControllerTests 테스트 클래스를 만들고 JUnit의 TestCase를 상속한다.
단위 테스트는 handleRequest()가 리턴하는 뷰이름이 hello.jsp인지 확인한다.
'springapp/test/springapp/web/HelloControllerTests.java':

테스트를 실행시키려면, build.xml에 테스트 태스크를 추가한다.
우선 junit.jar를 복사해서 넣는다.
테스트를 컴파일하고 실행시키는 태스크를 하나로 두는 대신 buildtests와 tests로 나눈다.
springapp/resourcs/devlib/를 두고 여기에 junit.jar를 넣는다.

build.xml에 다음의 내용을 추가한다.
<property name="resources.dir" value="resources"/>
<property name="devlib.dir" value="${resources.dir}/devlib"/>
...
<path id="devlib-classpath">
    <fileset dir="${devlib.dir}">
        <include name="*.jar"/>
    </fileset>
</path>

buildtests, tests 타겟에 <classpath refid="devlib-classpath"/>를 추가한다.

IDE에서 테스트를 실행시키려면 junit.jar를 빌드 패스에 추가한다.
'springapp/build.xml':

애자일의 또다른 practice는 지속적인 통합이다.
빌드할 때마다 테스트를 실행시켜서 개발이 진행되면서 어플리케이션이 제대로 동작하는지 확인할 수 있다.

1.10. View 작성하기

이미 앞에 언급된대로 hello.jsp로 포워딩한다.
war/에 둔다.
'springapp/war/hello.jsp':

1.11. 어플리케이션 컴파일, 배포

depoy 타겟을 실행시키고 reload 타겟을 실행시키면 빌드하고 Tomcat을 리로드한다.
Ant 출력과 Tomcat 로그를 확인한다.

1.12. 어플리케이션 테스트

브라우저로 http://localhost:8080/springapp/hello.htm 으로 들어가본다.

1.13. 요약

  • 설정이 제대로 되었는지 확인하기 위해 index.jsp를 만들었다. 나중에 실제 링크가 있는 페이지로 만들것이다.
  • DispatcherServlet과 springapp-servlet.xml
  • 지금은 단순히 ModelAndView만 리턴하는 HelloController. 나중에 model을 구현한다.
  • 뷰이름을 검증하기 위한 HelloControllerTests
  • 아주 간단한 hello.jsp



테스트 코드 작성을 위한 Workshop

캬~ 제목 좋다.
나도 배우면서 진행하고자 한다.
서로들 많은 영감을 얻었으면 한다.

W는 어제 과제를 내줬다.
일단 테스트를 하는 코드를 작성해보라고.
날짜형식에 관련된 유틸리티 메서드를 테스트하고 결과는 표준출력에 출력했다.
그리고 JUnit을 써보겠다고 자료를 출력하고 있다.[각주:1]
DAO를 테스트하는 코드를 작성해보라고 했음.

H는 테스트 코드를 작성했는데 방향을 조금 잘못 잡은듯 하다.
전체적인 개념을 설명해 줬는데 의외로 현재 DAO의 문제점을 빨리 파악했다.
그러나 어제 알려준 인터페이스에 대해 너무 집착을 한다.

아뭏튼 시작이 좋다.
나도 열심히 공부를 해야 하지만 중간중간 코칭을 제대로 하는게 중요할 듯 하다.
어차피 방향만 알려 줄뿐 나머지는 자신해야 하기 때문에.
  1. 좋은 현상이다. 결과를 떠나서 능동적으로 행동하고 있다. [본문으로]

Spring 2 + JPA + Tomcat

- 스프링 2와 JPA 시작하기

* 도메인 분석을 수행함
* 비즈니스 객체와 서비스를 구현함
* 비즈니스 객체에 대한 단위 테스트
* 스프링 JPA를 사용해 비즈니스 객체에 데이터 접근 코드 쉽게 추가
* 스프링 DAO(Data Access Object)를 사용해 서비스 구현
* DB2® Express-C와 연동한 서비스에 대한 통합 테스트 코드 작성
* 사용자 인터페이스에 기반을 둔 스프링 Model-View-Controller(MVC)를 위한 컨트롤러 생성
* 사용자 인터페이스를 위한 뷰(view) 디자인
* 애플리케이션을 위한 배치 가능한 WAR 파일 생성
* 아파치 톰캣(Apache Tomcat) 서버에 애플리케이션을 구성하고 배치함

- 도메인 모델 분석
직원엔터티에서 주소를 분리한다.
오퍼레이션을 정의한다.
Employee.java 에서 setEmpid() 를 제거한다.(JPA 에 의해서 관리된다.)

- JPA 어노테이션에 대한 설명
Employee와 Address 인스턴스가 일대일 관계(@OneToOne(casecade=CascadeType.ALL)) 어노테이션으로 기술되어)를 맺고 있는 것을 기억하자. 이 어노테이션은 Employee 객체를 대상으로 하는 모든 엔티티 매니저 오퍼레이션이 그 객체와 관련된 Address 객체에도 영향을 준다는 것을 의미한다. 이 말은 RDBMS에 Employee 기록을 추가하는 어느 작업이든지 그에 대응하는 Address 기록도 만들어지는 것을 뜻한다. 이것은 RDBMS에서 종종 찾을 수 있는 연속되는 삭제 참조 무결성 개념의 확장된 개념이라 보면 되겠다.

- HSQLDB 이용, DB2 로 변경

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

- SpringMVC

- 스프링 2를 위해 톰캣 준비하기
   1. 톰캣에 스프링 2 클래스로더 추가 : server/lib/spring-tomcat-weaver.jar, META-INF/context.xml
   2. 톰캣에 스프링 2 컨텍스트 로더 리스너(context loader listener) 추가
   3. 톰캣에 DB2 JDBC 드라이버 복사
   4. 톰캣을 위해 JNDI DB2 데이터소스 구성

- 참고
스프링 2와 JPA 시작하기 - 에러해결
Spring -JPA-Tomcat

[todo] 이거 설정만 바꾸면 다른 JPA 구현체로 바꿀수 있나?(2.0에서는 다른 구현체를 지원하지 않음. 2.5 는 에러남. 결국은 에러를 해결해야 하는데...)
[todo] 직접 해보기...금방될거야

유지보수 - 소스

- 아주 긴 클래스에서 개발자가 소스를 수정하다가 현재 작업중인 부분과 전혀 상관없는 아래 코드를 잘못 수정했다.
이런 실수를 방지할 수 있는 방법은 없을까?
- 아래와 같은 JSTL 이 지금까지 에러 안나고 있었음
이전 환경 : Tomcat 5.0 이나 Resin 3.0.25
Tomcat 6.0.18 에서 에러 발생