시간대 DB에서 우리나라 시간의 오류

변경이력

  • 2015/02/13

    • tzdata2014j에 반영 사실 갱신

    • 북한의 시간대에 대한 진행 상황 설명

2014년 2월, 회사의 기술블로그인 http://helloworld.naver.com에 Java의 날짜와 시간 API이라는 글을 기고한 적이 있습니다. 그 글을 쓰던 도중에 우리나라의 타임존 데이터에 대한 몇가지 의문을 가지게 되었지만 완벽히 해결하지는 못했었습니다.

얼마 전에 이 문제를 좀 더 깊이 파악을 해보았고, 원천 데이터인 IANA Timezone 데이터베이스에 패치를 전달해서 반영되었습니다. 조사과정에서 1920년대부터 1999년까지의 과거 뉴스를 조회하는 네이버의 뉴스라이브러리 서비스 ( http://newslibrary.naver.com/) 가 큰 도움이 되었습니다.

이 오류는 tzdata2014j에 반영되고, 이를 참조하는 Java, Android, FreeBSD에서도 2014년 11월경에 반영되었습니다.

플랫폼별로 반영시점은 다르겠지만, 다른 OS에서 이를 반영할 것으로 예상합니다.

현시점에서는 드물것 같지만, 혹시 우리나라의 1912 ~ 1980년대의 섬머타임과 시간대 변경에 영향받은 프로그램을 만드셨던 분이 있다면 참고로 알아둘만 합니다.

섬머타임의 오류 발견

처음 발견한 오류는 1988년의 섬머타임이 시작된 시간이였습니다. 아래 자료에 따르면 이 해의 섬머타임은 5월 8일 새벽 2시부터 시작되었습니다.

그러나 Java프로그램으로는 1988년 5월 7일 23시의 1시간 후가 5월8일 1시인것으로 나와서 00시를 기점으로 섬머타임이 적용되어 있습니다. 아래 테스트는 아직 오류수정이 정식 릴리즈되지 않은 지금 시점에서는 통과합니다.

@Test
public void shouldGetAfterOneHour() {
    TimeZone seoul = TimeZone.getTimeZone("Asia/Seoul");
    Calendar calendar = Calendar.getInstance(seoul);
    calendar.set(1988, Calendar.MAY , 7, 23, 0);
    String pattern = "yyyy.MM.dd HH:mm";
    String theTime = toString(calendar, pattern, seoul);
    assertThat(theTime).isEqualTo("1988.05.07 23:00");
    calendar.add(Calendar.HOUR_OF_DAY, 1);
    String after1Hour = toString(calendar, pattern, seoul);
    assertThat(after1Hour).isEqualTo("1988.05.08 01:00");}

(자세한 설명은 Java의 날짜와 시간 API,전체 소스는 OldJdkDateTest.java) 참조)

시간대 변경에 대한 정보는 윈도우즈, 안드로이드, OSX, 리눅스, Java, 오라클 등 거의 모든 플랫폼에서 Internet Assigned Numbers Authority (IANA)라는 조직에서 관리하는 시간대 데이터베이스를 원천으로 참조합니다. 처음에는 이 타임존 데이터베이스의 오류일지 아니면 다른 이유가 있을지 확신을 하지 못했습니다.

오류의 역사

Helloworld에 글이 나간 후에 이응준님께서 알려주셔서 우리나라의 섬머타임을 기록한 사람이 누구인지 알게 되었습니다. Github에 올라간 https://github.com/eggert/tz의 커밋로그를 바탕으로 이를 자세히 분석해봤습니다.

우리나라의 섬머타임에 대한 기록은 'Arthur David Olson’의 1988년 1월 3일의 커밋에 아래와 같이 처음으로 등장합니다.

# Republic of Korea. According to someone at the Korean Times in San Francisco,# Daylight Savings Time was not observed until 1987. He did not know# at what time of day DST starts or ends.# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/SRule ROK 1987 max - May Sun<=14 2:00 1:00 DRule ROK 1987 max - Oct Sun<=14 3:00 0 S

주석을 봐서는 섬머타임의 시작시기도 정확히 몰랐던 사람의 증언을 참고로 한 듯합니다. 그리고 1987년 이전에는 우리나라에 섬머타임이 없었다는 이야기도 사실과 다릅니다.

위의 코드로는 1987년부터 섬머타임이 계속되고 있다고 정의되었습니다. 1987,1988년에 우리나라에서 섬머타임이 실행되었으니 commit시점에서는 적어도 이 년도에 대해서는 맞는 데이터였습니다.

그러나 1988년 이후로도 우리나라에서는 섬머타임이 계속되어 있는것처럼 한동안 유지가 됩니다. 1993년에 이르러서야 이 데이터는 정정됩니다.

1993년 11월23일의 커밋으로 다음의 날짜가 다시 반영됩니다.

Rule ROK 1960 only - May 15 0:00 1:00 DRule ROK 1960 only - Sep 13 0:00 0 SRule ROK 1987 1988 - May Sun<=14 0:00 1:00 DRule ROK 1987 1988 - Oct Sun<=14 0:00 0 S

이 commit은 아래 2가지 오류를 담고 있습니다.

  • 1987~1988년도의 섬머타임은 시작시간 2시부터인데 0시부터로 표기되었습니다.

  • 새로 추가한 1960년의 섬머타임은 실제로는 5월1일부터 9월18일까지였습니다. 위키페디아와 옛날신문의 자료가 일치합니다.

  • 썸머타임 1일부터, 동아일보, 1960.05.01

  • 없어지는 섬머타임, 동아일보, 1960.09.18

이외에도 이 Commit은 우리나라 시간대 변경에 대한 많은 오류를 포함하고 있습니다. 섬머타임 외의 오류는 나중에 다시 살펴보도록 하겠습니다.

주석으로 볼때 위의 1993년 11월23일의 커밋Thomas G. Shanks의 The International Atlas의 제3판에 있는 내용을 반영한것을 보입니다. 주석에도 아래와 같이 미국이외의 타임존 정보는 별다른 명시가 없다면 이 책을 참고로 했다고 나옵니다.

# A good source for time zone historical data outside the U.S. is# Thomas G. Shanks, The International Atlas (3rd edition),# San Diego: ACS Publications, Inc. (1991).# Except where otherwise noted, it is the source for the data below.

지금 이 책은 6판까지 나와있고, 이후의 commit에서도 5판,6판을 따라서 수정한 내용이 보입니다.

그 이후 2012년 7월 18일의 커밋이 한번더 섬머타임 데이터를 수정했습니다. 1987년, 1988년의 표현규칙을 바꾼것으로 근본적인 오류가 수정되지는 않았습니다.

Rule ROK 1987 1988 - May Sun>=8    0:00 1:00 DRule ROK 1987 1988 - Oct Sun>=8    0:00 0 S

1960년 이전의 데이터까지 포함한다면, IANA 데이터베이스에서 우리나라의 섬머타임이 제대로 반영된 적은 한번도 없었던 것입니다.

패치 전달와 반영

조사결과 섬머타임의 오류를 확신하고, 이를 수정하는 패치파일을 직접 만들어서 시간대데이터를 관리하는 IANA에 메일(tz@iana.org )로 보냈습니다. 여러 옛날 신문들을 많이 찾아본결과 위키페이디아의 '한국표준시’페이지의 정보가 신뢰할만하다고 판단했습니다.

  • 1948.06.01. 00:00 ~ 1948.09.13. 00:00

  • 1949.04.03. 00:00 ~ 1949.09.11. 00:00

  • 1950.04.01. 00:00 ~ 1950.09.10. 00:00

  • 1951.05.06. 00:00 ~ 1951.09.09. 00:00

  • 1955.05.05. 00:00 ~ 1955.09.09. 00:00

  • 1956.05.20. 00:00 ~ 1956.09.30. 00:00

  • 1957.05.05. 00:00 ~ 1957.09.22. 00:00

  • 1958.05.04. 00:00 ~ 1958.09.21. 00:00

  • 1959.05.03. 00:00 ~ 1959.09.20. 00:00

  • 1960.05.01. 00:00 ~ 1960.09.18. 00:00

  • 1987.05.10. 02:00 ~ 1987.10.11. 03:00

  • 1988.05.08. 02:00 ~ 1988.10.09. 03:00

예를 들면 1948년의 정보는 1948년 6월1일자 동아일보 기사에서 확인할수 있습니다.

패치절차는 시간대데이터베이스의 소스에 있는 CONTRIBUTING파일에 잘 설명되어 있습니다. 정식절차와는 별도로 github에도 올려봤습니다. ( https://github.com/eggert/tz/pull/9 )

얼마 후 제가 보낸 패치를 포함하는 2014년 10월30일의 Commit이 올라왔습니다. 'Unreleased, experimental changes’라는 문구가 포함되었지만, 이를 뒤집는 증거가 발견되지 않는한 정식릴리즈에 포함될 것으로 예상합니다.

IANA쪽에서 이 수정을 받아준 Paul Eggert은 제가 섬머타임 변경의 근거로 보낸 위키페이디아의 '한국표준시’페이지를 보고 우리나라의 시간대 변경시점에 대한 오류도 추가로 수정을 했습니다.

시간대 변경시점의 오류

처음에 보낸 패치에는 포함되지 못했지만 섬머타임 외에도 우리나라 시간대 변경에 대한 의문도 있었습니다. "yyyy.MM.dd HH:mm (Z)"을 포멧으로 해서, 1954년, 1961년, 1968년의 특정시간과 그 때와 UTC와의 차이를 출력해보면, 아래와 같이 나옵니다. (소스는 TimeZoneChangePoint.java 참조 )

1954.03.20 22:59 (+0900)1954.03.20 23:00 (+0800)1961.08.09 23:59 (+0800)1961.08.10 00:30 (+0830)1968.09.30 23:59 (+0830)1968.10.01 00:30 (+0900)

이 소스의 결과는 1993년 11월23일의 수정 때 반영된 타임존DB의 정보에 의지합니다. 위의 결과라면 우리나라의 시간대 변경시점은 아래와 같습니다.

  • 1954년 : UTC+0900 → UTC+0800

  • 1961년 : UTC+0800 → UTC+0830

  • 1968년 : UTC+0830 → UTC+090

그러나 과거 신문에서 확인한 역사적 사실은 아래와 같습니다. 위키페디아의 내용과도 일치합니다.

즉 현재의 시간대데이터로는 1961~1968년사이는 아예 우리나라의 시간대가 잘못 계산되어 나온다는 것입니다.

이 부분은 섬머타임이 반영되는 것을 보고 조금 더 조사를 한 후에 추가 패치를 하려고 생각했었습니다. 기존 데이터가 그렇게까지 다 틀렸다는 것이 믿기가 어려웠고, 우리나라의 시간대 정보에 대한 거의 모든것을 한번에 고치기가 조심스러웠기 때문입니다. 그런데 Paul Eggert가 먼저 적극적으로 반영해주었습니다.

Paul Eggert는 이와 더불어 위키페이디아의 '한국표준시’페이지에 따르면 1912년에 UTC+0900로 변경이 있었는데, 1910년에도 같은 변경이 있었던것으로 기록된 부분이 혼동된다며 이를 명확히 확인해주었다면 좋겠다고 했습니다. 위키페디아에서 1910년도 변경의 근거로 든 '여적 표준시 변경, 경향신문, 2000-08-14.'라는 자료는 현재 인터넷으로 찾을 수 없어서 대신 여러 기록을 확인해보았습니다. 많은 자료가 1912년에 변경되었다는것으로 일치했고, 1910년도의 변경기록은 누군가가 한일합방 연도와 혼동한것이 아닐까하는 의견을 답장으로 보냈습니다.

북한의 타임존 데이터

또하나 의문이였던 점은 1993년 11월23일의 커밋으로 북한의 시간대가 1961년에 UTC+0900으로 변경되었다는 내용입니다. 그때 남한 쪽에서 시간대 변경이 있었는데, 당시 신문을 다 찾아봐도 남북한이 동시에 추진을 했다는 내용은 없었습니다.

Paul Eggert도 이를 이상하게 여겨 일단은 북한쪽은 1940년대 이후로 변화가 없는것으로 가정했다고 합니다.

While we’re in the neighborhood, it’s completely implausible that Pyongyang faithfully mimicked Seoul time during and after the Korean war (which is what Shanks says), so let’s remove that obviously-bogus guess.

저도 답장으로 북한쪽의 변경에 대한 의미있는 기록을 찾지 못했고, Paul Eggert의 가정에 동의한다는 내용을 보냈습니다.

tzdata2014j버전대로라면 1954년과 1961년 사이 서울과 평양사이에는 30분의 시차가 존재합니다. 이 것이 역사적 사실과 부합하는지 알아내려고 계속 알아보고 있는 중입니다. 현재 한국표준과학연구원과 통일부, 국정원에 문의를 했지만, 의미있는 답변은 받지 못했습니다. 특히 친절히 전화까지 해주신 통일부 직원분께 감사드립니다.

1954년과 1961년 사이에 남파/북파 간첩활동을 한 분이 있다면, 그 사실을 정확히 알고 있을 것 같기도 합니다. 그런데 과거 간첩사건을 조사해보니 생각보다 간첩들의 나이가 많아서 지금까지 생존한 분이 계실 가능성은 별로 없어보입니다.

마치며

재미있게도 위의 오류를 신고한지 얼마뒤인 2014년 11월 1일에 'Be less enthusiastic about Shanks and clarify UT vs UTC. '라는 제목으로 commit이 올라왔습니다. 우리나라 시간대에 대한 잘못된 정보의 출처였던 Shanks의 저서에 많은 오류가 있음을 지적하는 주석이 들어갔습니다. 아시아, 아프리카, 오스트랄라시아, 유럽 등 지역별 정보를 기록하는 모든 파일에 'A good source for time zone historical data outside the U.S. is..'라는 내용이 삭제되고, 'unfortunately this book contains many errors and cites no sources.'라는 문장이 추가되었습니다.

저의 신고가 영향을 준것인지는 알 수 없지만, 이 주석을 기점으로 기존의 데이터를 조금 더 의심하는 계기가 될 것으로 기대합니다.

비록 오래전 과거데이터라서 지금 시점의 영향성은 적지만, 믿음직한 표준데이터라고 생각했던 IANA Timezone DB에 이렇게 오류가 많았다는 점, 특히 우리나라 관련한 데이터에는 제대로 된 것이 거의 없었다는 사실은 놀랍습니다. 우리나라의 과거 자료와는 별도로, 국제화관련 개발을 하는 사람이라면 내 컴퓨터/내 담당서버에 들어와있는 타임존데이터베이스가 언제 시점인지, 업데이트는 잘 되어 있는지도 잘 확인해봐야겠습니다.

지금까지의 내용과 관련된 메일스레드는 아래와 같습니다.

Spring Loaded로 Tomcat 재시작 없이 수정한 클래스 반영하기

수정한 클래스 파일만 재로딩하는 Spring Loaded를 tomcat7-maven-plugin, Eclipse WTP와 함께 사용하는 방법을 정리합니다.

Note

2014년에 gist로 작성했던 글을 2026년에 이 블로그로 옮겼습니다. 발행 날짜는 gist 작성일(2014-10-13)에 맞췄고, 내용도 그 시점 기준입니다. 원본에 있던 Eclipse 설정 화면 스크린샷 3장은 원본 이미지 서버가 없어져 싣지 못했습니다.

Spring Loaded는 개발 환경에서 .java 클래스를 수정했을 때 변경된 클래스 파일만 재로딩하는 도구입니다. Local PC에서 수정과 Tomcat 재시작을 반복하는 시간을 줄여 줍니다.

다만 JRebel도 그러하듯이 모든 경우에 완벽한 리로딩이 되지는 않습니다. 메소드 추가·수정은 잘 반영됩니다. 그러나 아래와 같은 경우에는 자동 반영이 되지 않습니다.

  • 상속 구조의 변경

  • Reflection 정보가 Cache된 것

  • XML 설정 수정 (프레임워크에 특화된 구현이 들어가지 않으면 당연히 어렵습니다.)

그래도 많은 경우 Tomcat 재시작 없이 개발을 이어갈 수 있다면 생산성에 도움이 되리라 생각합니다. 이를 tomcat-maven-plugin과 함께 사용하는 방법을 정리합니다. Linux 명령어를 기준으로 썼지만, 윈도우에서도 같은 역할을 하는 작업을 수행하면 됩니다.

다운로드

참조할 디렉토리에 다운로드합니다. tomcat-maven-plugin을 사용할 예정이면 `pom.xml`이 있는 디렉토리에 받기를 권장합니다.

wget -O springloaded-1.2.1.jar http://search.maven.org/remotecontent?filepath=org/springframework/springloaded/1.2.1.RELEASE/springloaded-1.2.1.RELEASE.jar

Spring Loaded의 GitHub에서 최신 버전을 확인한 후 다운로드하는 것이 좋습니다.

tomcat7-maven-plugin으로 실행

1. 환경변수 설정

export MAVEN_OPTS="-javaagent:springloaded-1.2.1.jar -noverify"

2. pom.xml에 Tomcat7 plugin 추가

pom.xml
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <path>/</path>
    </configuration>
</plugin>

3. 실행

mvn tomcat7:run

Jetty나 Tomcat 6을 쓰고 싶다면 Local 개발환경에서 WAS를 띄우는 여러가지 방법을 참고합니다.

Eclipse WTP에서 실행

1. java agent 설정

Eclipse 메뉴의 Run > Run Configurations에서 Tomcat 실행 설정을 찾은 다음, Arguments 탭의 VM arguments란에 `-javaagent`를 추가합니다. 한 번이라도 Tomcat을 WTP로 실행해야 해당 설정이 생깁니다.

-javaagent:/다운로드경로/springloaded-1.2.1.jar -noverify

2. 기본 reload 설정 제거

Servers 뷰에서 Tomcat을 선택하고 Overview 탭의 Server Options란에서 'Modules auto reload by default’를 선택 해제합니다. Modules 탭의 해당 모듈 설정에서도 Auto reloading이 해제되어 있는지 확인합니다.

main 메소드를 직접 실행하는 경우

Spring Boot나 Embedded Tomcat, Jetty를 이용해서 main 메소드로 직접 WAS를 띄우는 경우도 있습니다. 이때도 Run > Run Configurations의 Arguments 탭에서 VM arguments란에 같은 -javaagent 설정을 추가합니다.

통합 테스트를 위한 내장 Tomcat, tomcat-bed

통합 테스트 안에서 내장 Tomcat을 띄워 JSP 렌더링까지 검증하는 tomcat-bed 예제를 설명합니다. Spring 테스트 컨텍스트에 bean으로 등록하면 여러 테스트가 WAS 하나를 공유하고, 포트가 이미 사용 중이면 떠 있는 서버를 그대로 씁니다.

Note

이 글은 2026년에 예전 예제 저장소들을 정리하면서 작성했습니다. benelog/tomcat-bed 저장소를 이 블로그 저장소의 examples/tomcat-bed로 병합했고, 발행 날짜는 원본 저장소의 마지막 커밋 날짜(2013-06-29)에 맞췄습니다. 본문도 그 시점의 기술 기준으로 서술했습니다.

tomcat-bed는 통합 테스트 안에서 내장 Tomcat을 띄우는 작은 유틸리티입니다. Spring 테스트 컨텍스트에 bean으로 등록하면 테스트가 시작될 때 WAS를 올리고 끝나면 내립니다. 별도의 배포 작업 없이 JSP 렌더링 결과까지 검증하는 UI 테스트를 JUnit 안에서 실행하려고 만들었습니다.

왜 만들었나

웹 계층을 검증하는 방식은 크게 세 가지입니다.

방식 장점 한계

배포된 서버 대상 UI 테스트

실제 운영과 같은 환경을 검증

테스트 전에 배포 작업이 필요하고, Test Coverage 측정이 어려움

Spring MVC Test (MockMvc)

서블릿 컨테이너 없이 빠르게 실행

Controller가 반환한 view 이름까지만 검증. JSP가 실제로 어떻게 렌더링되는지는 알 수 없음

내장 WAS + UI 테스트 (tomcat-bed)

배포 없이 JSP 렌더링까지 검증. EclEmma로 Eclipse에서 바로 커버리지 확인 가능

실제 Tomcat이 시작되므로 `MockMvc`보다 느림

Spring 3.2에 포함된 Spring MVC Test는 서블릿 컨테이너 없이 DispatcherServlet 계층을 검증하는 좋은 도구입니다. 다만 JSP 렌더링 결과는 검증 범위 밖입니다. 화면까지 확인하려면 실제 서블릿 컨테이너가 필요한데, 매번 배포해서 테스트하기는 번거롭습니다. 그래서 테스트 프로세스 안에서 Tomcat을 직접 띄우는 방식을 시도했습니다. Local 개발환경에서 WAS를 띄우는 여러가지 방법에서 다뤘던 내장 WAS 활용법을 테스트로 가져온 셈입니다.

핵심 클래스 WebApplicationServer

핵심은 WebApplicationServer.java 클래스 하나입니다. Tomcat 6의 org.apache.catalina.startup.Embedded API로 Engine, Host, Context를 조립합니다. 주요 부분만 옮기면 아래와 같습니다.

WebApplicationServer.java
public WebApplicationServer(String contextPath, int port, String appBase) {
	this.port = port;
	this.container = new Embedded();
	this.container.setName("TomcatEmbeddedServer");
	this.appContext = createAppContext(contextPath);
	Host localHost = createHost(appBase, appContext);
	Engine engine = createEngine(localHost);
	this.container.addEngine(engine);

	Connector connector = this.container.createConnector(
			localHost.getName(), port, false);
	this.container.addConnector(connector);
}

@PostConstruct
public void start() throws IOException, LifecycleException {
	log.info("Starting Tomcat... (port={})", port);

	if (isEmptyPort()) {
		this.container.start();
		this.running = true;
		this.servletContext = appContext.getServletContext();
	} else {
		log.info("The port({}) is already occupied.", port);
	}
}

설계 포인트는 세 가지입니다.

  • 배포 없는 실행 : `appBase`를 `src/main`으로 지정하면 war를 만들지 않고 소스 트리의 webapp 폴더를 그대로 서비스합니다.

  • 포트 점유 확인 : 지정한 포트가 이미 사용 중이면 내장 Tomcat을 시작하지 않습니다. PC에 개발용 WAS가 떠 있으면 그 서버를 대상으로 같은 테스트가 그대로 동작합니다.

  • 수명 주기 관리 : @PostConstruct/`@PreDestroy`로 시작과 종료를 선언해서, Spring 컨테이너가 bean의 수명에 맞춰 WAS를 올리고 내립니다.

Spring 테스트와 통합

`WebApplicationServer`를 테스트용 컨텍스트에 bean으로 등록합니다.

applicationContext-ui-test.xml
<util:properties id="testServer" location="classpath:testServer.properties" />

<bean id="was" class="net.benelog.tomcatbed.WebApplicationServer"
	c:contextPath="#{testServer.contextPath}"
	c:port="#{testServer.port}"
	c:appBase="src/main"/>

Spring TestContext 프레임워크는 같은 설정을 쓰는 테스트끼리 `ApplicationContext`를 캐싱해서 공유합니다. 덕분에 여러 테스트 클래스를 함께 실행해도 WAS는 한 번만 시작됩니다.

서버 접속 정보는 별도 속성 파일로 분리했습니다.

testServer.properties
contextPath=/
port=8080
baseUrl=http://localhost:8080

`baseUrl`을 개발 서버나 Staging 서버 주소로 바꾸면 같은 테스트를 다른 환경을 대상으로도 실행할 수 있습니다. 그 경우 해당 포트가 이미 사용 중이 아니므로 내장 Tomcat만 로컬에서 뜨지 않을 뿐, 테스트 코드는 동일합니다.

JWebUnit으로 화면 검증

테스트에서는 JWebUnit으로 실제 렌더링된 화면을 검증합니다. ZipCodePageTest.java는 폼 입력과 전송, 응답 화면 내용까지 확인합니다.

ZipCodePageTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/applicationContext-ui-test.xml"})
public class ZipCodePageTest {
	@Value("#{testServer.baseUrl}")
	String baseUrl;

	@Before
	public void prepare() {
		setBaseUrl(baseUrl);
		setScriptingEnabled(false);
	}

	@Test
	public void zipCodeForm() {
		beginAt("/zipCodeForm");
		assertFormPresent();
		assertSubmitButtonPresent();

		setTextField("zipCode", "121-270");
		submit();

		assertResponseCode(HttpStatus.OK.value());
		assertTitleEquals("Address");
		assertMatch("서울특별시 마포구 상암동");
	}
}

`@ContextConfiguration`으로 위의 테스트 컨텍스트를 지정하기만 하면, 테스트가 실행될 때 WAS가 준비됩니다. JSP가 렌더링한 제목과 본문 텍스트를 그대로 단언할 수 있다는 점이 `MockMvc`와의 차이입니다.

같은 예제 프로젝트에 두 방식을 나란히 두었습니다. HomeMvcTest.java는 Spring MVC Test로 Controller 계층을, HomePageTest.java는 내장 Tomcat 위에서 같은 화면을 검증합니다. 빠른 피드백은 `MockMvc`로, 화면까지 포함한 검증은 tomcat-bed로 나눠 쓰는 구성입니다.

한계

  • 실제 Tomcat이 시작되므로 Spring MVC Test보다 시작 속도가 느립니다.

  • 태그 라이브러리 선언 파일(*.tld)을 수동으로 등록해야 인식됩니다. 예제에서도 WEB-INF/tld에 JSTL과 Spring 태그의 tld 파일을 직접 넣었습니다.

  • Tomcat 6의 Embedded API를 사용했는데, Tomcat 7부터는 더 간결한 org.apache.catalina.startup.Tomcat 클래스가 이 역할을 대신합니다. 새로 시작한다면 그쪽이 출발점으로 적합합니다.

참고 자료


이 포스트는 Claude Code와 정상혁이 함께 작성했습니다.