Whiteship's Note

'2009/05'에 해당되는 글 41건

  1. 2009.05.29 소니 HDR-XR500 캠코더..지르다. (7)
  2. 2009.05.28 Getting Started with Spring Roo
  3. 2009.05.27 [JQuery] J쿼리 이용해서 속성 값 변경하기, 엘리먼트 셀렉션, 이벤트 추가하기 (2)
  4. 2009.05.26 [JavaScript] id값 변경하기 (4)
  5. 2009.05.26 [CSS] 탭 만들기 (2)
  6. 2009.05.25 바빴던 지난 주말 (4)
  7. 2009.05.25 프랑스도 멋진 나라구나.. (6)
  8. 2009.05.22 [CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기
  9. 2009.05.22 [CSS]그라데이션 배경 사용하기 (2)
  10. 2009.05.21 핀란드 멋진 나라네요. (11)
  11. 2009.05.19 WebTUnit 1.0 M1 배포합니다. (6)
  12. 2009.05.19 Double.MAX_VALUE는 좀 특이하군요 @_@ (4)
  13. 2009.05.19 WebTUnit에 CoC 적용 결과
  14. 2009.05.19 메이븐 배포나 설치시 소스 코드 배포하기 (2)
  15. 2009.05.18 Page Object 패턴을 이용한 웹 CRUD 테스트 with WebTUint
  16. 2009.05.15 XPath Path Expression 문법
  17. 2009.05.15 WebTUnit 사용 시나리오 3. 테스트 데이터가 필요 없는 경우
  18. 2009.05.15 WebTUnit 사용 시나리오 2. 웹 테스트 + 테스트 메서드 단위 데이터 관리
  19. 2009.05.15 웹 테스트 프레임워크(WebTUnit) 사용 시나리오 1. 웹 테스트 + 테스트 클래스 단위 데이터 관리 (2)
  20. 2009.05.14 웹 통합 테스트 프레임워크 개발 중 (4)
  21. 2009.05.14 메이븐 상식: 기본 페이스(phase) (2)
  22. 2009.05.13 내부에서 new 로 객체를 생성하는 코드 테스트 하기 (2)
  23. 2009.05.13 메이븐 프로젝트에서 단위/통합 테스트 어설프게 구분하기 (2)
  24. 2009.05.13 [Mockito] void 메서드 stubbing 새로운 방법
  25. 2009.05.12 JUnit Max 자동 실행 여부 설정하기
  26. 2009.05.12 Maven Embedder 사용해서 자바 코드로 메이븐 Phase 또는 Goal 실행하기
  27. 2009.05.12 Cargo의 TomcatManager
  28. 2009.05.11 JGit로 push 성공 기념샷. (6)
  29. 2009.05.11 통합 테스트 분리와 메이븐 관련 참조 할 글
  30. 2009.05.11 Cargo 메이븐 플러그인 설정하기

소니 HDR-XR500 캠코더..지르다.




500V나 520V가 아니라서 GPS는 안 된다는 점.. 이것만 빼면 완전 맘에 쏙 드는 제품입니다.

내일 결혼식에 있을 공연과 제주도 신혼여행을 위해 장만했는데, 앞으로 여러모로 요긴하게 써먹을 생각입니다. 예를 들어, 봄싹 스터디 발표를 이 녀석으로 녹화해서 공개한다던지.. 음하하하 발표자들이 좀 더 긴장하고 발표 준비를 해오겠군요.

사실 캠코더를 살 생각까진 없었고 빌려서 쓰려고 했는데, 지인을 통해 빌린 캠코더가 테이프를 사용해서 자료 보관이 힘들 뿐더러, 일본에서 직접 사오신 제품이라 조작법도 어렵고, 베터리도 방전이 심해서 5~10분을 못넘기는 관계로 후다닥 질렀습니다.

결혼하면서 별로 지른것도 없는데, 이 녀석을 혼수 삼으렵니다. 대충 이것 저것 조작해봤는데 HD 급으로 아주 선명하게 잘 찍어주더군요. 꺄오.. 동영상 찍다가 피사체가 웃으면 사진을 자동으로 찍어주질 않나, 손떨림 방지도 되고, 데이터가 내장된 하드 디스크에 저장되서 나중에 옮겨담기도 편하고 아주 좋아요.

한.. 일주일 정도 블로그를 비울 것 같습니다. 여행다니면서 중간 중간 볼거리들을 챙겨가야겠네요. JQuery API랑 ROO 관련 아티클과 소스코드 좀 뽑아갈까 합니다. 그럼 이만 일주일 뒤에 뵙겠습니다~ 캬캬캬


신고
top

TAG 캠코더

Getting Started with Spring Roo

Spring Roo/etc : 2009.05.28 19:26


참조 요약 편역: http://blog.springsource.com/2009/05/27/roo-part-2/

벤 알렉스가 다음 달에 결혼하나봅니다. 그래서 RSVP 받는 프로그램을 Roo로 만들어 볼까 한다는군요. 1석 2조네요. RSVP도 만들고 Roo도 소개하고. RSVP는 청첩장을 받은 것에 대한 응답으로 몇명이 참석할지 알려주는 응답이라고 봐도 되겠네요.

진행상황

오늘 M1 버전이 배포됐습니다. 31% 성능 향상, 이메일 서비스, JMS, 스프링 웹 플로, 시큐리티, 자동 셀레늄 테스트 지원등이 주요 기능이죠.

다음은 관련 사이트 입니다.
- 커뮤니티 포럼
- 이슈 트래커
- SVN 저장소
- 소스코드 모니터링
- Roo 트위터

프로젝트 이름 투표는 952명이 투표했고, 467표를 얻은 Spring Roo로 결정이 됐답니다.

설치하기

다운받고, 압축 풀고, bin 폴더를 path에 추가하면 끝입니다.
알파버전일 때는 ROO_HOME 환경 변수를 등록했었는데, 이건 필요없으니 지워야겠습니다.
STS 2.1.0.M1 버전을 사용할 때는 Roo 1.0.0.A2가 내장되어 있다고 합니다. STS 2.1.0.M2에는 Roo 1.0.0.M1이 내장 될 예정이라고 하네요. STS에서 Roo 쉘을 이용할 때는 탭키가 아니라 Ctrl+스페이스로 자동완성을 지원한다고 합니다. 이클립스 스타일에 따라서 말이죠.

애플리케이션 요구사항

Roo는 직접 코딩하고 커스터마이징 하는 것을 투명하고, 편하며, 자동생성과 잘 어울리도록 설계되었다는 겁니다.

청첩장을 아직 보내진 않았지만, 보낼 건데, 그 뒤에 "초대 코드"를 적어서 보낼 거라고 합니다. 그럼 받은 사람들은 "초대 코드"를 사이트에 입력한뒤에 RSVP 폼을 작성하도록 하는 것이죠. RSVP가 일종의 로그인 정보가 되고 그 뒤에 RSVP 폼에서 필요한 정보(참석할 인원, 하고 싶은 말 등)을 입력받는 겁니다.

프로젝트 만들기

$ mkdir wedding
$ cd wedding
$ roo

폴더를 만들고, 이동한 뒤, roo 쉡로 들어갑니다. 종종 hint를 입력해서 필요한 정보와 지시를 얻을 수 있습니다. 이 부분에 대한 한글 번역을 제공할 수 있다면 좋겠네요.

roo> create project -topLevelPackage com.wedding
Created /home/balex/blog/wedding/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/applicationContext.xml
Created SRC_MAIN_WEBAPP/WEB-INF
Created SRC_MAIN_WEBAPP/WEB-INF/wedding-servlet.xml
Created SRC_MAIN_WEBAPP/WEB-INF/web.xml
Created SRC_MAIN_WEBAPP/WEB-INF/jsp
Created SRC_MAIN_WEBAPP/WEB-INF/jsp/index.jsp
Created SRC_MAIN_WEBAPP/WEB-INF/urlrewrite.xml

프로젝트를 만듭니다. 이 때 최상위 패키지 정보를 줄 수 있군요. 메이븐 기본 폴더 구조로 프로젝트가 생성되고 스프링 설정 파일들이 보이네요. 이것으로 일단 기본 스프링 3.0 웹 애플리케이션이 만들어졌고, URL rewriting, 애노테이션 기반 클래스패스 스캐닝, 의존성 주입 등의 기능을 갖추었습니다.

roo> install jpa -provider HIBERNATE -database HYPERSONIC_PERSISTENT
Created SRC_MAIN_RESOURCES/META-INF
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/database.properties
Managed SRC_MAIN_RESOURCES/applicationContext.xml
Managed ROOT/pom.xml

이번에는 JPA를 추가했습니다. 영속성 관리를 하이버네이트로 하고, DB는 hsql을 사용하겠다고 했군요. 맨 밑에 두줄은 Managed로 표시되어 있는데, 어떤 문제가 있을 되돌리기 위해 Roo가 관리하는 파일을 표시해 둔 거라고 합니다. Roo가 생성한 코드는 성능 최적화를 고려하여 toString()에서 리플렉션을 사용하지 않는다고 하는군요. 흠.. 코드가 궁금해지네요. 아니면 지금 번역을 잘못한건지.. @_@

Roo does everything from avoiding reflection to optimizing string operations in your toString() methods (and everything in between) to maximise runtime performance of your applications.

데이터베이스 설정을 확인할 수 있습니다.

roo> database properties
database.driverClassName = org.hsqldb.jdbcDriver
database.password =
database.url = jdbc:hsqldb:${user.home}/wedding
database.username = sa

변경할 수도 있습니다.

roo> database set -key database.url -value jdbc:hsqldb:/home/balex/our-wedding
Managed SRC_MAIN_RESOURCES/database.properties

물론 Roo를 사용하지 않고 IDE에서 직접 수정해도 됩니다. 단, 이렇게 커맨드를 이용할 수 있게 만든 이유는 스크립트를 제작할 수 있도록 하기 위해서 랍니다.

엔티티 만들기

roo> new persistent class jpa -name ~.domain.Rsvp
Created SRC_MAIN_JAVA/com/wedding/domain
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp.java
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Plural.aj
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Entity.aj
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_ToString.aj
Created SRC_MAIN_JAVA/com/wedding/domain/Rsvp_Roo_Configurable.aj

프로젝트를 만들 때 입력한 최상위 프로젝트 밑에 domain 패키지를 만들고 그 아래 Rsvp 도메인을 추가했습니다. ~가 바로 그 최상위 프로젝트를 나타내는 단축키이고, Rsvp 도메인을 만들면서 AspectJ 파일 네 개를 자동생성했네요. 이 파일들은 STS 1.0+에서 자동으로 숨겨주기 때문에 이클립스에서 그냥 보시면 보이지가 않습니다. hide 옵션에서 *.aj 파일 체크를 해제해야 볼 수 있죠.

roo> add field string code -notNull -sizeMin 1 -sizeMax 30
roo> add field string email -sizeMax 30
roo> add field number attending -type java.lang.Integer
roo> add field string specialRequests -sizeMax 100
roo> add field date jpa confirmed -type java.util.Date

필드를 추가합니다. 이 때 검증 관련 옵션을 주는데 이 옵션들은 JSR 303 Bean Validation 스펙을 이용합니다. 이를 사용하여 영속 계층에서도 검증을 하고, 웹에서도 검증을 하고, DDL을 생성할 때도 이용합니다. Roo를 사용할 때 얻을 수 있는 장점 중 하나가 바로 이렇게 별다른 수고 없이도 자연스래 표준을 이용하게 된다는 겁니다.

제대로 동작하는지 확인하기

roo> new integration test

통합테스트를 만듭니다. 아마도 DB, 도메인, 서비스를 연계한 테스트겠지요?

roo> new controller automatic ~.web.RsvpController

이번에는 컨트롤러를 만드는데, 자동 모드로 만듭니다. 스프링 3.0 REST 지원을 사용합니다. 사용자가 사용하게 될 URL은 완전한 RESTful 이며 깔끔하고 잘 정의된 URL이 될 겁니다. 이런 자동 웹 단은 다음의 경우에 유용합니다.

roo> new selenium test -controller ~.web.RsvpController

이번에는 앞에서 만든 컨트롤러에 대한 셀레늄 테스트를 만듭니다. 그래서 갑자기 컨트롤러를 만들었군요. @_@

이제 테스트를 실행할 차례입니다. roo 쉘에서 잠깐 나가야겠네요.

roo> quit
$ mvn test
$ mvn tomcat:run

roo 쉘에서 나가서, mvn test로 아마 통합 테스트까지 실행 한 뒤, 웹 테스트를 위해서 일단 톰캣을 가동합니다. 이상태에서 http://localhost:8080/wedding에 접속하여 애플리케이션이 잘 동작하나 확인할 수 있습니다.

$ mvn selenium:selenese

자 이번에는 자동으로 만들어진 셀레늄 테스트를 실행합니다. 뭐.. 잘 되겠지요. 자동으로 만든 코드를 자동으로 만든 테스트로 테스트를 하는데, 제대로 안 되면... 배포를 안 했겠죠.. @_@.. 이건 뭐 그냥 쑈를 위해 해본 듯한 느낌이지 진짜 테스트 같다는 느낌은 들지 않는군요.

보안과 로깅

roo> configure logging -level DEBUG -package WEB

웹 단이 잘 동작하나 보기 위해 로딩을 DEBUG 모드로 설정했네요. Log4J 기반 로깅을 사용한답니다..

다음은 시큐리티인데, 스프링 시큐리티를 한 줄로 설치할 수 있습니다. 참 쉽죠~

roo> install security

install web flow, install jms도 이런 식으로 한방 설치가 가능하다고 하는데 이건 뭐 거의.. Grails를 봤을 때의 충격과 맞먹는 기능입니다. 멋져부러~~!!!

컨트롤러, 동적 파인더, 이메일 기능 관리하기

roo> new controller manual -name ~.web.PublicRsvpController

이번에는 자동모드가 아니라 직접 코딩으로 만들 컨트롤러를 추가합니다. 이 컨트롤러는 HTTP GET과 POST 요청을 다룹니다. 두 개의 메서드가 자동으로 컨트롤러 클래스에 추가되어 있다고 합니다.

GET 요청이 오면 특정 "초대 코드"에 대한 RSVP를 가져오는 것입니다. 스프링 시큐리티를 사용하여 "요청 코드"를 일종의 username으로 취급하여 사용자가 로그인 할 수 있게 하고, 로그인 한 사용자의 "요청 코드
로 DB에서 RSVP 정보를 가져오는 역할을 할 겁니다. 이때 "요청 코드"로 RSVP를 찾아오는 JPA QL을 작성할 필요가 있겠지만. 이것 역시 Roo가 도와줄테니 걱정할 필요 없습니다.

만들고자 하는 동적 파인더를 찾아봅니다.

roo> list finders for -class ~.domain.Rsvp -filter code,equ
findRsvpsByCodeEquals(String code)
findRsvpsByCodeNotEquals(String code)

캬.. 이것참 멋집니다. 찾고자 하는게 딱 있네요. filter 옵션 사용법만 잘 익히면 원하는 파인더를 뚝딱 만들어 낼 수 있다니.. 멋집니다. 멋져.

roo> install finder -finderName findRsvpsByCodeEquals

이런 식으로 필요한 파인더를 추가할 수 있습니다.

POST 요청이 오면 RSVP 정보를 추가하고 이메일로 알림을 받고 싶습니다. 그럼 이제 이메일 공급자를 설치하고 email 필드를 컨트롤러에 추가하겠습니다.

roo> install email provider -hostServer 127.0.0.1
roo> add field email template -class ~.web.PublicRsvpController

너무 쉬워서 말이 안나오네요. Roo에서 Gmail을 사용하여 이메일을 보내는 방법도 간단한가 봅니다.

IDE 통합

roo> quit
$ mvn eclipse:eclipse
$ roo

roo 쉘에서 나가서 이클립스 프로젝트 설정을 추가한다음 다시 roo로 돌아옵니다. 이제 이클립스에서 import하면 되겠죠.

마지막 단계

이제는 이클립스에서 필요한 파일들을 수정, 추가하고 필요한 코딩을 하면 될 것 같습니다. 위에서 설명했던 컨트롤러 코딩을 해야겠죠. 시큐리티 설정도 손봐야겠구요.

   <http auto-config="true">
       <form-login login-processing-url="/static/j_spring_security_check" login-page="/static/login.jsp" authentication-failure-url="/static/login.jsp?login_error=t"/>
       <logout logout-url="/static/j_spring_security_logout"/>
       <intercept-url pattern="/rsvp/**" access="ROLE_ADMIN"/>
       <intercept-url pattern="/resources/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
       <intercept-url pattern="/static/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
       <intercept-url pattern="/**" access="IS_AUTHENTICATED_REMEMBERED" />
   </http>

   <authentication-provider>
       <user-service>
           <user name="admin1234" password="ignored" authorities="ROLE_ADMIN"/>
        <user name="user12345" password="ignored" authorities="ROLE_USER"/>
        <user name="user67890" password="ignored" authorities="ROLE_USER"/>
    </user-service>
</authentication-provider>

시큐리티 설정을 손봤습니다. 로그인 할 때 사용자의 password는 무시하고 username으로 "요청 코드"를 입력하면 로그인 되도록 수정했네요.

src/main/webapp/login.jsp 뷰도 수정해야겠죠. <input name="j_password" type="hidden" value="ignored"/> 이렇게 추가하고 기존에 "j_password" 레이블을 가진 <div>는 삭제합니다. 자 이제 시큐리티 설정은 끝났고, 컨트롤러를 코딩합니다.

@RequestMapping("/publicrsvp/**")
@Controller
@SessionAttributes("rsvp")
public class PublicRsvpController {

    @Autowired
    private transient MailSender mailTemplate;

    @RequestMapping
    public String get(ModelMap modelMap) {
        modelMap.put("rsvp", getRsvp());
        return "publicrsvp";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String post(@ModelAttribute("rsvp") Rsvp rsvp, ModelMap modelMap) {
      rsvp.setConfirmed(new Date());
        if (rsvp.getId() == null) {
            rsvp.persist();
        } else {
            rsvp.merge();
        }
        if (rsvp.getEmail().length() > 0) {
            sendMessage("Ben Alex <ben.alex@springsource.com>", "RSVP to our wedding", rsvp.getEmail(), "Your RSVP has been saved: " + rsvp.toString());
        }
        modelMap.put("rsvp", rsvp);
        return "thanks";
    }

    private Rsvp getRsvp() {
        Rsvp rsvp = new Rsvp();
        try {
            String code = SecurityContextHolder.getContext().getAuthentication().getName();
            rsvp.setCode(code);
            // Cast due to http://java.sun.com/javaee/5/docs/api/javax/persistence/Query.html#getSingleResult()
            rsvp = (Rsvp) Rsvp.findRsvpsByCodeEquals(code).getSingleResult();
        } catch (PersistenceException ignored) { /* no Rsvp for this code was found, so start a new Rsvp */ }
        return rsvp;
    }

    private void sendMessage(String mailFrom, String subject, String mailTo, String message) {
        SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(mailFrom);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setTo(mailTo);
        simpleMailMessage.setText(message);
        mailTemplate.send(simpleMailMessage);
    }
}


GET 요청을 다룰 때는 getRsvp() 메서드를 보시면 아시겠지만, 위에서 설명했던대로, 시큐리티를 이용해서 현재 로그인한 사용자의 "요청 코드"를 가져오고, 위에서 만들었던 파인더(findRsvpsByCodeEquals)를 이용해서 rsvp를 가져옵니다. 그리고 최종적으로 "publicrsvp" 라는 뷰 이름을 반환하죠.

POST 요청이 오면 날짜를 설정하고, 기존에 있던 정보면 수정하고 없던거면 새로 추가한 다음에 이전에 만들었던 이메일 공급자를 사용해서 이메일을 보내고 "thanks" 라는 뷰 이름을 반환합니다.

이젠 최종 뷰를 만들어줘야 합니다. thanks 뷰는 src/main/webapp/WEB-INF/index.jsp를 thanks.jsp로 수정해서 만듭니다. 사용자가 입력한 RSVP 정보를 보여주기 위해 "Your RSVP has been confirmed: ${rsvp}". 이 한 줄을 추가하는 것도 괜찮겠죠.

다음은 publicrsvp 뷰를 만듭니다. 이 뷰는 src/main/webapp/WEB-INF/rsvp/create.jsp를 src/main/webapp/WEB-INF/publicrsvp.jsp 이 파일로 변경합니다. 그리고 이 파일을 수정해서 "code"와 "confirmed" 섹션을 삭제합니다. 또한 폼 액션도 위에서 작성한 컨트롤러가 다룰 수 있도록 "/wedding/publicrsvp" 이렇게 수정해줍니다.

마지막으로 src/main/webapp/WEB-INF/urlrewrite.xml 이 파일을 열고  / 대신에 /WEB-INF/jsp/index.jsp 이렇게 리다이렉트할 페이지를 수정해 줍니다.

이제 "mvn tomcat:run"로 톰캣을 실행하던지..
이클립스에서 Run As -> Run on Server를 하던지
STS에서 Spring Tools -> Open Roo Shell로 roo 쉘을 열고 "deploy -server someServer"를 이용하면 됩니다.

roo 쉘을 이용해서 프로젝트 빌드 배포를 할 수 있을지 의문이 드네요.
roo를 제대로 활용하려면 스프링 3.0 역시 제대로 알고 있어야겠습니다.
거저 얻을 수 있는 것에도 한계가 있어보입니다. 이것 저것 수정해서 입맛에 맞게 변경하려면 스프링 학습은 필수라는 거..

끝으로.. mvn package로 WAR 파일을 만들어서 tc 서버나 dm 서버에도 배포할 수 있다는 거~~


ps1: 새로운 기술을 보거나 공부할 때 마다 기억나는 말이 있는데, "맨날 다른 기술 공부하기만 하면, 자기 자신의 것은 없고 따라갈 줄만 알게 되지 않겠냐?" 라는 건데, 제 생각엔 뭘 보고 배워야 자기 자신의 것도 만들 수 있게 되지 아무것도 모르는 상태에서 어떻게 뭘 만들어 내겠냐는 겁니다. 좋은 건 좋다고 인정하고, 배울 건 배워야 성장하지 않을까요. 백년 만년 자기가 접하는 제한된 환경 속에서 제한된 기술만 가지고 노는건 자기 스스로를 우물안에 가두는 꼴이 아닐런지 말입니다.

 ps2: 결혼식 하기전에 오랜만에 스크린캐스팅을 하나 찍어볼까 생각중입니다. 이래저래 스프링 소스는 참 재미난 것들을 많이 제공해 주네요. 멋져!
신고

'Spring Roo > etc' 카테고리의 다른 글

스프링 Roo 1.0.0.RC1 배포~  (0) 2009.07.22
Getting Started with Spring Roo  (0) 2009.05.28
스프링 Roo petclic 예제 실행 성공  (2) 2009.04.30
Roo 설치하기  (0) 2009.04.30
스프링 Roo 프로젝트 이름 투표하기  (0) 2009.04.30
Spring Roo가 나왔습니다.  (0) 2009.04.30
top

TAG ROO

[JQuery] J쿼리 이용해서 속성 값 변경하기, 엘리먼트 셀렉션, 이벤트 추가하기

View/JavaScript : 2009.05.27 16:13


attr을 사용하면 됩니다. 이전에 작성한 탭 만들기 글에서 a 엘리먼트의 onclick 속성을 사용하여, 자바스크립트 함수를 호출했었는데, J쿼리를 이용해서 그런 부분을 완전히 자바스크립트 쪽으로 떼어 낼 수 있게 되었습니다.

            $(document).ready(function() {
                $("#topnav a").bind("click", function () {
                    var id = $(this).parents("li").attr("id");
                    $("body").attr("class", id);
                });
            });

이 간단한 코드에 위 제목에서 언급한 모든 것들이 들어있습니다. 먼저, 이벤트 등록을 html에서 완전히 분리할 수 있게 도와주는 코드는 바로..

$(document).ready(function() {

});

이 녀석입니다. 이 안에서 이벤트 등록 작업을 해주면,

<a href="#" onclick="changeMenu('report');">

HTML에서 이런 코드를 작성하지 않아도 됩니다.

다음은 이벤트를 등록하는 코드입니다.

$("#topnav a").bind("click", function () {

});

그 전에 셀렉션을 보겠는데, #topnav a 이 부분은 topnav id를 가진 엘리먼트 하위의 a 엘리먼트를 모두 선택하라는 것입니다. API를 보면 더 다양한 방법들이 예제와 함께 잘 나와있습니다.

다시 이벤트 코드로 돌아가서 bind는 특정 이벤트에 어떠한 함수를 호출하도록 등록하는 함수인데, 이것을 특정 이벤트에 맞게 줄여서 다음과 같이 쓸 수도 있습니다.

$("#topnav a").click(function () {

});

간단하죠. click은 클릭하라는게 아니라 click 이벤트 핸들러를 등록하는 겁니다.

var id = $(this).parents("li").attr("id");

이 코드에서는 parents를 사용해서 자신을 감싸고 있는(여기서 자신은 사용자가 클릭한 a 엘리먼트겠죠.) 엘리머먼트 중에 li를 선택하고, 그 엘리먼트의 id 속성 값을 가져옵니다.

attr(속성이름)은 보시다시피 속성의 값을 가져오는 게터와 비슷합니다.

이와 반대로 세터 역할을 하는 함수도 역시 attr인데 사용법이 조금 다릅니다. 이번에는 인자를 하나 더 줍니다.

$("body").attr("class", id);

이렇게, attr(속성이름, 값) 형태로 사용하면 세터같이 동작합니다. 참~~ 편리하군요.


ps: 원래는 body의 class가 아니라 id를 변경하도록 코드를 작성했었는데, 잘 되지 않아서 class를 이용해봤는데 잘 동작하네요. 왜 그런지는 모르겠습니다. $(document).ready(function(){}); 이 것을 사용하지 않으면 id 변경도 잘 되는데 말이죠.. 저것과 관련이 있어 보입니다.
신고
top


[JavaScript] id값 변경하기

View/JavaScript : 2009.05.26 16:52


<a href="#" onclick="changeMenu('report');">KOMA-REPORT</a>

화면에서 changeMenu('report'); 형태로 자바스크립트를 호출하게 하고, 자바스크립트 함수를 다음과 같이 정의합니다.

var changeMenu = function(id) {
    document.body.id = id;
}

간단하더군요.
신고
top


[CSS] 탭 만들기

View/HTML/CSS : 2009.05.26 14:53




탭에 들어갈 요소들을 일단 ul li 엘리먼트를 사용하여 내용을 정의한다.

<ul id="nav">
  <li id="t-email"><a href="">E-MAIL</a></li>
  <li id="t-reportl"><a href="">KOMA-REPORT</a></li>
  <li id="t-em"><a href="">KOMA-EM</a></li>
</ul>

이 상태에서는 세로로 쭉 나열하며 목록에 점 하나씩을 달고 있는 형태가 된다.

이제 ul에 width를 넓히고, li들을 왼쪽에 차곡 차곡 떠있게 설정한다.

            #nav {
                float: left;
                width: 100%;
                margin: 10px 10px 0 0;
                padding: 10px 0 0 0;
                list-style: none;
                background: url(/images/new/bt_line.png) repeat-x bottom left;
            }
           
            #nav li {
                float: left;
                margin: 0;
                padding: 0;
                font-size: 80%;
            }

이때 float을 사용하고 있는 li를 감싸는 nav에도 꼭 float을 설정해야 페이지가 깨지지 않는다.

다음은 a를 탭 모양으로 다듬어 준다. 패딩 주고, 패딩, 마진을 주고, 탭 전체를 클릭할 수 있게 설정한다.

            #nav a {
                float: left;
                display: block;
                margin: 0 1px 0 0;
                padding: 4px 8px;
                color: #333;
                text-decoration: none;
            }

마우스를 올렸을 때 다른 모습으로 효과를 준다.

            #nav a:hover {
                color: #333;
                background: #edf4fc;
                border: #9fc5f6 solid 1px;
                border-bottom: none;
            }

클릭한 탭의 모양이 변경되도록 설정한다. 이 부분이 조금 재미있는데, 클릭을 하면 자바스크립트로 body의 id 값을 변경하고, 해당 id의 body 밑에 있는 특정 탭의 id에 있는 a를 css로 꾸며 주면 된다.

            body#em #t-em a{
                color: #333;
                background: #edf4fc;
                border: #6593cf solid 1px;
                border-bottom: none;;
            }

이런 형태다. body#em #t-em a 이것을 #em #t-em a 이렇게 써도 상관없으며, 모든 탭에 적용해야 하기 때문에.

            #email #t-email a,
            #report #t-report a,
            #em #t-em a {
                color: #333;
                background: #edf4fc;
                border: #6593cf solid 1px;
                border-bottom: none;;
            }

이렇게 설정할 수 있다.
신고

'View > HTML/CSS' 카테고리의 다른 글

[IBM DW] HTML5 navigator  (0) 2010.07.06
[CSS] 탭 만들기  (2) 2009.05.26
[CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기  (0) 2009.05.22
[CSS]그라데이션 배경 사용하기  (2) 2009.05.22
XPath Path Expression 문법  (0) 2009.05.15
Chapter 14. Image Replacement  (0) 2008.03.31
Chpater 13. Styling Text  (0) 2008.03.31
Chapter 10. Applying CSS  (0) 2008.03.26
Chapter 9. Minimizing Markup  (0) 2008.03.23
Chapter 8. More Lists  (0) 2008.03.23
Chapter 7. Anchors  (0) 2008.03.23
top

TAG CSS,

바빴던 지난 주말



금요일 "형제는 용감했다."  이벤트에 당첨되어 S석 두장을 공짜로 얻은 와이프 덕분에 오랜만에 뮤지컬을 보러갔지만, 내심 별로 기대는 하고 있지 않았습니다. 그런데 웬걸... 뮤지컬도 나름 재미있었고, 그 보다는 정준하 때문인지... 무슨 날이었는지.. 노홍철, 유재석, 차태현 등 엄청나게 많은 연예인들이 몰려왔더군요. @_@ 노홍철과 유재석을 진짜 말그대로 코앞에서 봤습니다. TV에 나오는 모습하고 똑같더군요.



토요일 "함사세요". 조금 멀리 떨어진 오산까지 친구들이 와서 "함사세요" 파티를 해줬습니다. 조용한 동네고 이런 것을 해본적도 없다고 하는데 어떨런지 걱정했지만, 주민들께서 잘 봐주셔서 별일은 없어서 다행이었습니다. 친구들도 처음해보는거라 어색할 줄 알았는데, 능숙하게 잘들 버팅기고 놀다가 들어오더군요. 덕분에 와이프 친구들이 고생한 것 같아 맛있는 저녁식사라도 대접해야겠습니다. 이 날의 꽃은 장모님이 마련해주신 완전 완전 완전 맛있는 갈비찜, 감자탕, 골뱅이 무침이었습니다. 저는 자리에 있던 모든 친구과 돌아가며 1:1 대작을 하느라 많이 먹진 못했지만 정말 음식 맛이 예술이었습니다. +_+ 그렇게 마시다가 혼자 취할 뻔 한 것을 장인어르신께서 친구들과 글라스로 소주 원샷 1:1 대작으로 살려주셨습니다. 핫핫핫. 한가지 아쉬운건 사진을 많이 못남겼다는 것? 암튼.. 친구들아.. 너네들 함들어갈땐 내가 함지기를 해줄께. 좋치? 흐흐흐 기대해...



일요일 "담양 나들이" 와이프가 운전을 하고 저는 술에 취해 뻗은채로 옷만 갈아입고 담양으로 내려갔습니다. 죽녹원과 메타세콰이어길에가서 자연을 즐기다 왔는데, 이 전날의 피로와 더운 날씨, 수 많은 인파로 인해 많이 고생했지만, 그 만큼 좋은 추억거리를 하나 만들고 돌아와서 뿌듯했습니다. 이 날도 장모님댁에서 저녁과 단잠을 신세지고, 매형이 오산에서 집까지 데려다 주시는 수고를 해주셨습니다. 와이프에게 좋은 남편이 되는 것이 이런 호의에 보답하는 길이겠지요. 열심히 잘 사는 모습으로 보답해야겠습니다.

몸이 고단해질 정도로 바빴던 주말이 가고 새로운 한주가 시작됐네요. 이번 주 토요일 결혼식을 위해서라도 컨디션 조절을 잘해야겠습니다.


신고
top


프랑스도 멋진 나라구나..

모하니?/Watching : 2009.05.25 08:56


피의 숙청. 언론인 수천명을 총살 시켜 깨끗하게 새 출발한 프랑스와 만주 벌판에서 독립군을 죽이던 사람이 대통령을 하고 아직도 그를 찬양하는 사람들이 있는 한국의 차이~



덤으로.. '언론은 어떻게 조작되는가..'



이런 나라에서 정의를 부르시던 별이 지다니.. 슬픈 일입니다.
신고

'모하니? > Watching' 카테고리의 다른 글

초고속 로보트 손  (0) 2009.09.15
허경영의 콜미  (0) 2009.08.13
한국의 비양심  (0) 2009.07.24
러시아의 양심  (4) 2009.07.24
콜 오브 듀티(COD) Modern Warfare 2 어여 나와라~  (0) 2009.06.08
프랑스도 멋진 나라구나..  (6) 2009.05.25
핀란드 멋진 나라네요.  (11) 2009.05.21
못살겠다 대한민국  (7) 2009.04.17
한국에도 이런 개그가 통할까?  (0) 2009.01.15
http://www.parleys.com 멋진 싸이트  (2) 2008.09.27
베토벤 바이러스 잼나네요.  (2) 2008.09.24
top


[CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기

View/HTML/CSS : 2009.05.22 09:59



링크를 걸면 보통 텍스트 부위만 클릭할 수 있는데, 해당 블럭을 클릭할 수 있게 수정하면 좀 더 편리함.

display:block;
=> a 엘리먼튼에 display:block을 적용함.

마우스를 올렸을 때 배경색이나 배경 이미지를 변경하여 현재 선택하려는 요소가 다른 것과 구분되게 함.

a:hover { background-color: #94B8E9;}
=> hover 유사 클래스를 사용하여 간단하게 롤오버 적용.
신고

'View > HTML/CSS' 카테고리의 다른 글

[IBM DW] HTML5 navigator  (0) 2010.07.06
[CSS] 탭 만들기  (2) 2009.05.26
[CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기  (0) 2009.05.22
[CSS]그라데이션 배경 사용하기  (2) 2009.05.22
XPath Path Expression 문법  (0) 2009.05.15
Chapter 14. Image Replacement  (0) 2008.03.31
Chpater 13. Styling Text  (0) 2008.03.31
Chapter 10. Applying CSS  (0) 2008.03.26
Chapter 9. Minimizing Markup  (0) 2008.03.23
Chapter 8. More Lists  (0) 2008.03.23
Chapter 7. Anchors  (0) 2008.03.23
top


[CSS]그라데이션 배경 사용하기

View/HTML/CSS : 2009.05.22 09:54



가로 폭 1px 짜리 그라데이션 이미지를 만들고, 가로로 쭉 반복 시켜줌.

background: url(배경이미지) repeat-x;

=> 배경 이미지를 가로로 반복시킴. 세로로 반복하는 repeat-y도 있음.

배경이 커서 그라데이션 이미지로 커버가 안 될 때는 그라데이션이 끝나는 지점과 같은 색을 배경으로 깔아줌.

background: 색상코드 url(images/new/level1_bg.png) repeat-x;



신고

'View > HTML/CSS' 카테고리의 다른 글

[IBM DW] HTML5 navigator  (0) 2010.07.06
[CSS] 탭 만들기  (2) 2009.05.26
[CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기  (0) 2009.05.22
[CSS]그라데이션 배경 사용하기  (2) 2009.05.22
XPath Path Expression 문법  (0) 2009.05.15
Chapter 14. Image Replacement  (0) 2008.03.31
Chpater 13. Styling Text  (0) 2008.03.31
Chapter 10. Applying CSS  (0) 2008.03.26
Chapter 9. Minimizing Markup  (0) 2008.03.23
Chapter 8. More Lists  (0) 2008.03.23
Chapter 7. Anchors  (0) 2008.03.23
top


핀란드 멋진 나라네요.

모하니?/Watching : 2009.05.21 09:43






한국은 어찌되려나... @_@
열공 해야지.

신고
top

TAG 핀란드

WebTUnit 1.0 M1 배포합니다.

모하니?/Coding : 2009.05.19 21:43


아래 매뉴얼을 참조하세요.
영어로 작성했는데, 너그러이 봐주세요.

이번 주 내로 배포하고 싶은.. M2 버전에서는 다음 두 가지를 중점접으로 다루겠습니다.
- 샘플 애플리케이션을 추가
- Jetty 추가

저저번주 금요일부터 오늘까지 달렸으니까..
금,  월~금, 월, 화. 8일이네요.
이제 쬐끔 쓸만해져서 공개했습니다.

웹 테스트 하실 때 조금이나마 보탬이 되었음 합니다.
막심 므라비차의 축하공연을 들으며 찬찬히 읽어 보세요. 간단합니다.



0. add repository setting to pom.xml or settings.xml

        <repository>
            <id>opensprout nexus</id>
            <name>OpenSprout Nexus public</name>
            <url>http://www.opensprout.org/nexus/content/groups/public</url>
        </repository>

        WebTUnit is provided by OpenSprout Nexus.

1. add dependency to pom.xml

        <!-- WebTUnit -->
        <dependency>
            <groupId>org.opensprout</groupId>
            <artifactId>webtunit</artifactId>
            <version>1.0-M1</version>
        </dependency>

2. add cargo-maven-plugin and maven-surefire-plugin to pom.xml

    2-1. cargo-maven-plugin configuraion

        <build>
        ...
            <plugin>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <version>1.0.1-SNAPSHOT</version>
                <configuration>
                    <wait>false</wait>
                    <container>
                        <containerId>tomcat6x</containerId>
                        <type>installed</type>
                        <home>tomcat/apache-tomcat-6.0.18</home>
                    </container>
                    <deployer>
                        <type>installed</type>
                    </deployer>
                    <configuration>
                        <properties>
                            <cargo.servlet.port>8080</cargo.servlet.port>
                        </properties>
                    </configuration>
                </configuration>
                <executions>
                    <execution>
                        <id>start-container</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>start</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>stop-container</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>stop</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        First, you must set up your tomcat home to <home> element above or,
        just download and unzip tomcat archive to project/tomcat folder.

        If you set <wait> to true, then when you run a test server by 'mvn cargo:start',
        the console will be wait untile you stop the process by CTRL + C.
        This is useful when you want to test on Eclipse by CTRL + ALT + X -> T or CTRL + F11.
        But, you shold be careful when you use phase that through pre-integration-test phase.
        That process will stop and wait in pre-integration-test until you stop the test server.

        By default setting, you can use cargo with phases thar through pre-integration-test phase.
        For example, when you run 'mvn verify', you will pass pre-integration-test phase,
        but you will not be stopped by process, because it dooesn't wait.
        This will help you when you set up this project in continuous integration environment.

    2-2. maven-surefire-plugin configuration

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>**/*WebTest.java</exclude>
                    </excludes>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <phase>integration-test</phase>
                        <configuration>
                            <excludes>
                                <exclude>none</exclude>
                            </excludes>
                            <includes>
                                <include>**/*WebTest.java</include>
                            </includes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        ...
        </build>

        If you want to use another naming pattern, or package pattern,
        change '**/*WebTest.java' value to what you want.

3. make some web test with webdriver.

    @RunWith(WebTestRunner.class)
    @WarConfiguration("opensprout")
    public class MemberWebTest {

        @WebTest
        public void memberPages(){
            WebDriver driver = new HtmlUnitDriver();
            driver.get("http://localhost:8090/springsprout/member/list.do");
            MemberListPage listPage = PageFactory.initElements(driver, MemberListPage.class);
            assertEquals(2, listPage.getTableRows());
        }
    }

    If you want to feel comfortable when you write some web test codes,
    I recommend Page Object Pattern(http://code.google.com/p/webdriver/wiki/PageObjects).
   
    You can also use @DataConfiguration when you want to input and delete some test data.
    Check some usecases.
    - http://whiteship.me/2237
    - http://whiteship.me/2238
    - http://whiteship.me/2239

4. run test.

    Open a console, type 'mvn verify'.
    Or, modify, cargo-maven-plugin's <wait> to true, and run it with JUnit in Eclipse.
   
5. give me a feedback

    http://github.com/whiteship/WebTUnit/issues
   

신고
top


Double.MAX_VALUE는 좀 특이하군요 @_@

Java : 2009.05.19 21:07


System.out.println(Double.compare(Double.MAX_VALUE, Double.MAX_VALUE - 1.0));

이렇게 하면 무슨 값이 출력 될까요? 앞에 있는 인자가 더 크니까 양수가 나와야 합니다.
그러나 해보시면 아시겠지만, 0이 나옵니다.

난 너무 커서 1 같이 작은 수는 빼봤자 그게 그거야...

라는 건가요.. 이건 좀 @_@
왜이러는 걸까요?
정확하게 비교하려면 어떻게 해야 할까요?

한가지 찾은 방법은 longValue() 이용해서 long으로 바꾼 다음에 계산하는 겁니다.
그러나.. 불편하자나요~
신고
top


WebTUnit에 CoC 적용 결과

모하니?/Coding : 2009.05.19 15:39


한 가지를 더 수정해서 이제는 WarConfiguration 설정이 더 간편해졌다. 8080 포트를 사용하여 웹 테스트를 할 때는 appName이라는 속성을 명시하지 않고 그냥 애플리케이션 이름만 명시하면 된다.

@RunWith(WebTestRunner.class)
@WarConfiguration("springsprout")
@DataConfiguration
public class MemberWebTest {

    @WebTest
    public void memberPages(){
       ...
    }
}

이제 한 가지만 더 정리하면 1.0-M1 버전을 공개할 수 있을 듯 하다. 캬캬캬

--------------------------------
@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration(dataType=DataType.XML, location="org/springsprout/testData.xml")
public class MemberWebTest {

    @WebTest
    public void memberPages(){
       ...
    }

설정하는 방법을 위와 같은 형태에서 아래와 같이 변경됐습니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration
public class MemberWebTest {

    @WebTest
    public void memberPages(){
          ...
    }
}

이 것이 전부입니다.

먼저, 바뀐 내용 중 하나는 파일 확장자를 통해 데이터 타입을 짐작한다는 것입니다. CoC라기 보다는 아예 바뀐 내용입니다.

1. 적용한 CoC는 우선, 기본 테스트 데이터 파일 이름을 testData.xml로 생각하며, 테스트하려는 클래스와 동일한 패키지에 들어있다고 가정합니다.

2. 하지만, /를 사용하여 파일 이름을 명시 했을 때에는 해당 패키지 경로에서 테스트 파일을 찾게 합니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration(fileName="integration/member/testData.xml")
public class MemberWebTest {

    @WebTest
    public void memberPages(){
          ...
    }
}

이런식으로 말이죠.
신고
top


메이븐 배포나 설치시 소스 코드 배포하기

Build/Maven : 2009.05.19 11:11


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

이렇게 플러그인 하나만 추가하면 끝납니다.
참~ 쉽죠~

jar 골에 maven-source-plugin을 실행하도록 설정한 겁니다. 따라서 mvn install 또는 mvn delpoy를 할 때 소스도 같이 올라가게 되고, 이 라이브러리를 참조하는 쪽에서..

            <plugin>
                <artifactId>maven-idea-plugin</artifactId>
                <version>2.1</version>
                <configuration>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                    <dependenciesAsLibraries>true</dependenciesAsLibraries>
                    <useFullNames>false</useFullNames>
                </configuration>
            </plugin>

이런 식으로 설정해 두었다면, 라이브러리르 가져올 때 소스 코드도 같이 가져오게 됩니다. 그럼 이클립스에서 소스 코드 참조도 쉽게 할 수 있겠죠.
신고
top


Page Object 패턴을 이용한 웹 CRUD 테스트 with WebTUint

모하니?/Coding : 2009.05.18 20:32


참조
http://code.google.com/p/webdriver/wiki/PageObjects
http://code.google.com/p/webdriver/wiki/PageFactory

화면의 페이지를 나타내는 Page 객체들을 작성합니다. 화면에서 테스트할 주요 엘리먼트들은 WebElement로 표현하고, 각각의 엘리먼트를 애노테이션으로 찾을 수 있게 id나 name 또는 xpath를 사용하여 지정해 줍니다.
public class MemberForm {

    protected WebElement name;

    protected WebElement email;

    protected WebElement password;

    @FindBy(how = How.ID, using = "name.errors")
    protected WebElement nameError;

    @FindBy(how = How.ID, using = "email.errors")
    protected WebElement emailError;

    @FindBy(how = How.ID, using = "password.errors")
    protected WebElement passwordError;

    @FindBy(how = How.XPATH, using = "//input[@type='submit']")
    protected WebElement submit;

    public WebElement getName() {
        return name;
    }

...

}

원랜 Page 클래스에 있어야 할 속성들인데, 다른 Page에서도 공통으로 사용하는 속성들이라 상위 클래스로 빼냈습니다. 애노테이션을 붙이지 않으면, 자동은 화면에서 클래스의 변수명에 해당하는 id를 가진 엘리먼트를 찾아줍니다.
 
그 다음으로, 페이지에서 일어나는 사용자 액션을 메서드로 표현합니다.

public class MemberAddPage extends MemberForm {

    private WebDriver driver;

    public MemberAddPage(WebDriver driver) {
        this.driver = driver;
    }

    public MemberAddPage addFail() {
        name.sendKeys("keesun");
        submit.submit();
        return PageFactory.initElements(driver, MemberAddPage.class);
    }

    public MemberListPage addSuccess() {
        password.sendKeys("123");
        email.sendKeys("keesun@whiteship.me");
        submit.submit();
        return PageFactory.initElements(driver, MemberListPage.class);
    }

}

이것을 이용하여 다음과 같은 테스트를 작성할 수 있습니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration(dataType=DataType.XML, location="integration/member/testData.xml")
public class MemberWebTest {

    @WebTest
    public void memberPages(){
        WebDriver driver = new HtmlUnitDriver();
        driver.get("http://localhost:8080/springsprout/member/list.do");
        MemberListPage listPage = PageFactory.initElements(driver, MemberListPage.class);
        assertEquals(2, listPage.getTableRows());

        MemberAddPage addPage = listPage.toAddForm();
        assertNotNull(addPage);

        MemberAddPage failedAddPage = addPage.addFail();
        assertNotNull(failedAddPage);
        assertEquals("required", failedAddPage.getEmailError().getText());
        assertEquals("required", failedAddPage.getPasswordError().getText());

        listPage = failedAddPage.addSuccess();
        assertNotNull(listPage);
        assertEquals(3, listPage.getTableRows());

...

}

물론, WebTUnit이 없다면, 수동으로 서버를 켜고, 데이터 넣고, 저 테스트를 실행하고, 다시 테스트 데이터를 정리하고, 서버를 내리는 작업을 반복해야겠지만.. WebTUnit이 있기 때문에 메이븐 콘솔에서 mvn verify를 실행하기만 하면 위의 작업들을 자동화 할 수 있습니다. 조금더 빠르고 이클립스에서 실행해 보고 싶다면, pom.xml을 약간 수정하여 cargo.wait 속성을 true로 바꾸고 mvn cargo:start로 서버를 실행한 다음, 이클립스에서 JUnit 테스트로 실행하면 됩니다.
신고
top


XPath Path Expression 문법

View/HTML/CSS : 2009.05.15 19:55


참조: http://www.w3schools.com/XPath/xpath_syntax.asp

자주쓰는 표현식

노드이름: 해당 이름의 모든 하위 노드를 선택한다.
/: 최상위 노드에서부터 선택한다.
//: 현재 문서에서 해당 노드에 대응하는 모든 모드를 (위치에 상관없이)선택한다.
.: 현재 노드를 선택한다.
..: 현재 노드의 상위 노드를 선택한다.
@: 속성을 선택한다.


와일드 카드

*: 모든 엘리먼트 노드
@*: 모든 속성 노드
node(): 모든 종류의 노드

<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

  <book>
    <title lang="eng">Harry Potter</title>
    <price>29.99</price>
  </book>

  <book>
    <title lang="eng">Learning XML</title>
    <price>39.95</price>
  </book>

</bookstore>

표현식 사용 예제

bookstore: bookstore 엘리먼트의 모든 하위 노드를 선택한다.
/bookstore: bookstore를 선택한다.
//bock: 모든 book 엘리먼트를 선택한다.
bookstore//book: bookstrore 하위에 있는 book 엘리먼트를 선택한다.
//@lang: 모든 lang 속성을 선택한다.

/bookstore/book[1]: bookstore 하위의 book 엘리먼트 중에 첫 번째 것을 선택한다.(IE5는 0이 첫 번째 것을 가리키는데 W3C 표준은 1이 맞다.)
/bookstore/book[last()]: bookstore 하위의 book 엘리먼트 중에 마지막 것을 선택한다.
/bookstore/book[last()-1]: 마지막에서 하나 전 것을 선택한다.
/bookstore/book[position()<3]: 처음 두 개를 선택한다.
//title[@lang]: lang이라는 속성을 가진 모든 title을 선택한다.
//title[@lang='eng']: lang 속성의 값이 eng인 모든 title을 선택한다.
/bookstore/book[price>35.00]: price 엘리먼트의 값이 35보다 큰 (bookstore 하위의) book을 선택한다.
/bookstore/book[price>35.00]/title: price 엘리먼트의 값이 35보다 큰 (bookstore 하위의) book의 title을 선택한다.

와일드 카드 사용 예제

/bookstore/*: bookstore 하위의 모든 엘리먼트를 선택한다.
//*: 문서에 있는 모든 엘리먼트를 선택한다.
//title[@*]: 어떤 속성이라도 가지고 있는 title 엘리먼트를 선택한다.

표현식 연산자 |

//book/title | //book/price: book에 있는 모든 title과 price 엘리먼트를 선택한다.
//title | //price: 문서에 있는 모든 title과 price를 선택한다.
/bookstore/book/title | //price: bookstore에 있는 book에 있는 모든 title과 문서에 있는 모든 price를 선택한다.

Webdriver에서 xpath를 사용하여 엘리먼트를 선택할 수 있는 기능을 제공함.

예)  submit = driver.findElement(By.xpath("//input[@type='submit']"));
신고

'View > HTML/CSS' 카테고리의 다른 글

[IBM DW] HTML5 navigator  (0) 2010.07.06
[CSS] 탭 만들기  (2) 2009.05.26
[CSS] 링크 적용 범위 넓히기, 롤오버 효과 주기  (0) 2009.05.22
[CSS]그라데이션 배경 사용하기  (2) 2009.05.22
XPath Path Expression 문법  (0) 2009.05.15
Chapter 14. Image Replacement  (0) 2008.03.31
Chpater 13. Styling Text  (0) 2008.03.31
Chapter 10. Applying CSS  (0) 2008.03.26
Chapter 9. Minimizing Markup  (0) 2008.03.23
Chapter 8. More Lists  (0) 2008.03.23
Chapter 7. Anchors  (0) 2008.03.23
top

TAG xpath

WebTUnit 사용 시나리오 3. 테스트 데이터가 필요 없는 경우

모하니?/Coding : 2009.05.15 14:05


제일 간단한 경우 입니다. 테스트 데이터가 필요 없기 때문에 @WarConfiguration만 사용하면 됩니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
public class SampleWebTest {

    @WebTest
    public void sinario1(){
        System.out.println("test1");
    }

    @WebTest
    public void sinario2(){
        System.out.println("test2");
    }

}

이렇게만 하면,

1. WAR 패키징
2. WAR 배포
3. 테스트~
4. WAR un배포

과정을 거치게 됩니다~ 이건 뭐 너무 간단해서 더 설명할 것도 없네요~


이제부터 본격적인 테스트는 WebDriver나 Selenium을 이용해서 작성하면 되겠죠. ㄱㄱㅆ~
신고
top


WebTUnit 사용 시나리오 2. 웹 테스트 + 테스트 메서드 단위 데이터 관리

모하니?/Coding : 2009.05.15 12:50


이번에는 이전 시나리오와 비슷하지만, 테스트 데이터를 클래스 단위가 아니라 메서드 단위 즉, JUnit에서 테스트 단위로 관리하는 방법입니다. 아직은 미완성이라고 볼 수 있는데, 지금 상태에서도 아래와 같이 코딩을 한다면, 이 시나리오가 가능합니다.

@RunWith(WebTestRunner.class)
@WarConfiguration("springsprout")
//@DataConfiguration(fileName="testData.xml")
public class SampleWebTest {

    @WebTest
    public void sinario1(){
        DataManager dm = new DefaultDataManager("integration/sample/testData1.xml", DataType.XML);
        dm.insertTestData();
        System.out.println("test1");
    }

    @WebTest
    public void sinario2(){
        DataManager dm = new DefaultDataManager("integration/sample/testData2.xml", DataType.XML);
        dm.insertTestData();
        System.out.println("test2");
    }

}

@DataConfiguration을 클래스에서 제거하면 되고, 소스코드에서 직접 DataManager API를 사용하여, 테스트 데이터를 넣을 수 있습니다. 위 예제에서는 두 개의 테스트에서 각각 다른 테스트 데이터를 넣고 있습니다.


테스트 데이터를 매번 지우고 싶다면, deleteTestData() 메서드를 이용해도 되지만, insertTestData가 내부적으로 DBUnit의 CLEAN_INSERT를 이용하기 때문에 그럴 필요는 없습니다.

이 코드는 차후에 JUnit 4.7의 인터셉터 기능을 이용해서 개선할 예정입니다. 지금은 스냅샷 정도록 생각해주세요
신고
top


웹 테스트 프레임워크(WebTUnit) 사용 시나리오 1. 웹 테스트 + 테스트 클래스 단위 데이터 관리

모하니?/Coding : 2009.05.15 11:36


해당 테스트 클래스를 웹 테스트 하고, 그 안에 있는 모든 테스트들이 공통의 데이터를 이용할 때 사용할 수 있습니다. 단, 주의할 것은 테스트들 사이에 순서가 없기 때문에(JUnit과 동일) 테스트 데이터를 잘못 조작하면 테스트끼리 의존성 생겨 실패할 수 있습니다. 테스트 마다 각자의 테스트 데이터를 사용하는 시나리오는 다음에 살펴보겠습니다. 이 시나리오는 테스트 데이터를 조작하지는 않고 주로 참조 용으로 테스트 하는 경우에 적당합니다.

@RunWith(WebTestRunner.class)
@WarConfiguration("springsprout")
@DataConfiguration(fileName="integration/sample/testData.xml")
public class SampleWebTest {

    @Before
    public void setUp(){
        System.out.println("===================================");
        System.out.println("===================================");
    }

    @WebTest
    public void test1(){
        System.out.println("test1");
    }

    @WebTest
    public void test2(){
        System.out.println("test2");
        fail("for test");
    }

    @After
    public void tearDown(){
        System.out.println("***********************************");
        System.out.println("***********************************");
    }

    @Test
    public void noTest(){
        System.out.println("this will not be print");
    }

}

이렇게 했을 경우
1. sprignsprout라는 이름의 WAR 파일을 생성하고,
2. 배포하고,
3. integration/sample/testData.xml에 있는 데이터를 DB에 넣고
4. 테스트를 쫙 실행(순서 무작위, JUnit 동작 방식을 따름), 각각의 테스트는 @WebTest를 붙여줌. @Test는 동작하지 않습니다. @Before, @After, @BeforeClass, @AfterClass, @Ignore 모두 적용 됨. 딱 하나. @Test 대신 @WebTest를 사용하면 됨. @Test를 사용해도 되지만, 테스트 구분을 위해.. 차후에 WebTest관련 기능을 추가할 때 유리할 듯..
5. 테스트가 끝나면(중간에 몇 개가 실패하더라도), 테스트 데이터를 삭제하고,
6. WAR를 unploy합니다.

물론 세부적 예외가 언제 발생하느냐에 따라 그 처리가 조금씩 달라집니다. 지금도 계속해서 이부분을 작업하고 있으니 자세한 설명은 나중에~


신고
top


웹 통합 테스트 프레임워크 개발 중

모하니?/Coding : 2009.05.14 23:10


웹 통합 테스트를 지시 받고, 몇일 전 삽질부터 시작해서 오늘까지 조금 열심히 달렸습니다. 오늘은 오후 6시쯤 되니까 머리가 아파서 더 못 앉아 있겠더군요. 아침에 오자마자 만들기 시작해서 조금 하다 보면 오후 1, 2시가 금방 되고, 그러면 밥 먹고 나서 또 조금 하다 보면 4, 5시가 되고, 또 조금 하다 보면 7, 8시가 되니까 하루가 정말 짧더군요. @_@

아직도 많이 손봐야 하지만, 이제 조금 윤곽이 잡혔습니다.
@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration(dataType=DataType.XML, location="integration/sample/testData.xml")
public class IndexPageWebTest {

    @WebTest
    public void sample(){
        WebDriver driver = new HtmlUnitDriver();
        driver.navigate().to("http://localhost:8080/springsprout/index.do");
        assertTrue(driver.getTitle().equals("SpringSprout"));
    }

}

WebDriver를 이용한 초간단 웹 테스트 코드입니다. 이렇게 설정한 다음 테스트를 실행하면..
1. 현재 프로젝트를 WAR 패키징을 합니다.
2. 생성한 WAR를 테스트용 톰캣 서버에 springsprout 컨텍스트 패스로 배포합니다.(maven/tomcat6x/webapp/springsprout)
3. 배포가 잘 됐으면, 테스트 데이터를 넣어줍니다.
4. 이제 테스트를 실행합니다.
5. 테스트 데이터를 삭제합니다.
6. 앞서 배포한 WAR 파일을 undeploy 합니다.

여기서 4번에 해당하는 코드만 작성하면 됩니다. 나머지는 애노테이션만 붙여주면 되죠. 테스트 케이스 마다 서버를 켰다 껐다 하는 건 좀 무리고, WAR만 그때 그때 배포하도록 했습니다.

@RunWith(WebTestRunner.class)
@WarConfiguration(appName="springsprout")
@DataConfiguration(dataType=DataType.XML, location="integration/sample/testData.xml")
public class IndexPageWebTest {

    @WebTest
    public void test1(){
   
    }
   
    @WebTest
    public void test2(){
       
    }

}

이렇게 테스트를 하나 더 추가하면? WAR 배포 이후에 두 개의 테스트를 모두 실행한 다음에 WAR를 unploy합니다.

약간의 변화를 줄 수 있습니다. 테스트 데이터 입력이 필요 없다면, @DataConfiguration을 생략해도 됩니다. 그리고 테스트 서버 포트를 기본으로 8080을 사용하는데, 그 값을 @WarConfiguration의 port 속성에 줄 수 있습니다. 그럼 해당 포트에 배포를 시도하죠. 물론 그럴 때 해당 포트에 서버가 실행되고 있지 않다면, debug 모드의 로깅과 적절한 이름의 RuntimeException이 발생합니다.

꾸준히 가꿔야겠지만, 이제 내일 부터는 이녀석을 이용해서 본격적으로 웹 통합 CRUD 테스트를 만들고, CI를 해보려고 합니다.

얘 때문에 조금이라도 뒤적여 본 것들은 다음과 같습니다.
- JUnit 4.6
- Spring Test
- Cargo
- DBUnit
- WebDriver
- Maven Surefire Plugin
- Appfuse
- Maven Embedder

지난주 금, 월, 화, 수, 목.. 거의 일주일이네요.
개발이 참 더디고 어설프네요. ㅎㅎ 갈 길이 멀었습니다. @_@
신고
top


메이븐 상식: 기본 페이스(phase)

Build/Maven : 2009.05.14 13:36


참조: http://www.sonatype.com/books/maven-book/reference/lifecycle.html#lifecycle-sect-structure

달달달 외워야 할 것.


맨 처음에 clean을 하지않는 군요. target 폴더를 깨끗하게 청소하고 빌드 하려면, mvn clean verify 형태로 입력하면 되겠습니다. 그럼 위에서부터 쫘르륵~~ 실행해주죠.

validate ->
source -> resource -> compile -> classes ->
test-source -> test-resource -> test-compile -> test ->
pre-pacage -> package -> post-package ->
pre-intefration-test -> integration-test -> post-integration-test ->
verify -> install -> deploy

대충 이렇군요.

신고
top


내부에서 new 로 객체를 생성하는 코드 테스트 하기

모하니?/Coding : 2009.05.13 23:53


어렵죠? 어떻게 해야될까요? 제가 오늘 맞딱드린 상황은 생성자 내부에서 필요한 필드를 세팅하는데 new 를 사용해서 객체를 생성하더군요. 그런데 그 필드들이 굉장히 중요한 역할을 해주고 있었습니다. 하지만 너무 복잡해서 그 녀석들 그대로 테스트를 하면 테스트 하는 범위도 너무 넓고 이미 다른 곳에서 여러번 테스트 해 본 것들이라 테스트에 오히려 방해가 되는 수준까지 이르렀습니다.

    public WebTestRunner(Class<?> klass) throws InitializationError {
        super(klass);
        WebTestConfiguration wtc = klass.getAnnotation(WebTestConfiguration.class);
        if(wtc == null)
            throw new IllegalStateException();

        dataManager = createDataManager((String)getValue(wtc, "testDataLocation"));
        warManager = createWarManager((String)getValue(wtc, "appName"));
    }

대충 이렀습니다. 저 두 녀석을 mockup 하고 싶은데, 저 녀석들을 생성하는데 필요한 또 다른 설정까지 있습니다. 어떻게 해야 될까요?

결과물은 자꾸 늦게 나오는 것 같고, 시간은 마구 달려가고, 정신은 점점 혼미해지고, 어깨는 누가 짓누르는 것 같은 고통 속에서 생각난건, 테스트 하는 대상의 스텁을 만들고 스텁으로 테스트하고 싶은 부분을 테스트하면서 원본에 테스트 결과를 반영하는 것이었습니다. 그리 아름다운 방법은 아닌 것 같지만, 유용하게 써먹었습니다.

이런 스텁 구현체를 만들었죠.

    public WebTestRunnerStub(Class<?> klass) throws InitializationError {
        super(klass);
        // WebTestConfiguration wtc =
        // klass.getAnnotation(WebTestConfiguration.class);
        // if(wtc == null)
        // throw new IllegalStateException();
        //
        // dataManager = createDataManager((String)getValue(wtc,
        // "testDataLocation"));
        // warManager = createWarManager((String)getValue(wtc, "appName"));
    }

src-springsprout-WebTestRunner (원본 테스트 대상)
test-springsprout-WebTestRunnerStub (원본 테스트 대상의 스텁 구현체)
                         -WebTestRunnerTest (WebTestRunnerStub에 대한 테스트)

이 상태에서 테스트 코드를 작성합니다,

    WebTestRunnerStub runner;
    WarManager mockWarManager;
    DataManager mockDataManager;

    @Before
    public void setUp() throws InitializationError{
        runner = new WebTestRunnerStub(this.getClass());
        mockWarManager = mock(WarManager.class);
        mockDataManager = mock(DataManager.class);
        runner.setWarManager(mockWarManager);
        runner.setDataManager(mockDataManager);
    }

이런식으로 mocking을 할 수 있습니다. 이 뒤에는 뭐~ 걍 하고 싶을대로 하면 되는거죠.

이렇게 해두면, 일단 네비게이션은 그다지 불편하지 않습니다.
- 테스트 코드에서 스텁으로의 이동은 Ctrl+클릭을 이용하면 되고,
- 테스트 코드에서 원본 대상으로의 이동은 Ctrl+J(MoreUnit 플러그인 설치 해야함)를 사용하면 됩니다.

테스트용 코드를 마구 심어놓을 수 있습니다.
- 스텁을 어떻게 구현해서 지지고 볶던 제 맘이고, 실제 코드에 아무런 영향도 주지 않습니다.
- 따라서 저처럼 Sysout을 좋아하시는 분들은 맘대로 원한는 곳에 Sysout을 심어 두어도 관계 없습니다.

하지만 다소 큰 단점이 있습니다. 눈으로 동기화를 해줘야 합니다.
- 원본과 스텁이 똑같을 필요는 없지만, 테스트 하는 부분에 있어서 중요 로직은 동일해야겠죠.

젤 좋은 방법은 IoC가 가능한 구조로 바꾸는 건데 JUnit의 BlockJUnit4ClassRunner 클래스를 상속하여 만든 클래스라서...  IoC 구조로 만들어 사용하기가 좀 애매하네요..@_@

좋은 방법은 아닌거 같지만 나름 편리한 방법이오니, 테스트하기 불편한 클래스의 테스트가 급하신 분들은 이용해 보세요. ㅋㅋ
신고
top


메이븐 프로젝트에서 단위/통합 테스트 어설프게 구분하기

Good Tools : 2009.05.13 17:58


참조: http://wiki.rodcoffin.com/index.php?title=Maven_Integration_Testing

안타깝게도 maven-surefire-plugin에는 아직 이 둘을 구분지을 만한 기능이 없습니다. 그럼에도 불구하고 기존에 제공하는 기능들을 잘~ 조합하여 원한 것과 비슷한 결과를 도출해 냅니다. 결코 원하던 결과는 아니지만, 뭐 그나마 그래도 다행인 결과이기는 합니다.

결론부터 보자면

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>**/*WebTest.java</exclude>
                    </excludes>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>test</goal>
                        </goals>
                        <phase>integration-test</phase>
                        <configuration>
                            <excludes>
                                <exclude>none</exclude>
                            </excludes>
                            <includes>
                                <include>**/*WebTest.java</include>
                            </includes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

이런 식으로 설정해야
<단위 테스트>
mvn test를 실행 할 때 WebTest로 끝나는 자바 파일은 테스트 대상에서 제외하고,
<통합 테스트>
mvn integration-test를 실행 할 때는 모든 WebTest로 끝나는 자바 파일을 포함하여 모든 것들을 다 테스트 합니다.

그나마 다행이라고 한 이유는 통합 테스트를 할 때 단위 테스트를 실행하는 건 시간 상 메모리 상 분명히 오버헤드에 해당하지만, 통합 테스트 자체가 이미 상당량의 시간과 메모리를 잡아 먹을 것이기 때문에, 마치 큰 산에다가 흙 한 줌 더한 꼴로 볼 수 있기 때문이죠. 또 하나 테스트 실패/성공 측면에서 보더라도 이미 단위 테스트 단계를 통과하고 온 것들이라면 이 단계에서 실패할 가능성은 거의 없다고 봐도 무관하겠죠.

그래도 좀.. 잘 나눌 수 있게 sufire:integration-test 같은 골을 추가해주거나, 설정을 좀 더 잘할 수 있게 기능을 추가해줬으면 좋겠습니다.

ps: mutual exclusive 설정 같은걸 추가해주면 안 되남..
신고
top


[Mockito] void 메서드 stubbing 새로운 방법

Good Tools : 2009.05.13 16:41


참조: http://mockito.googlecode.com/svn/branches/1.4/javadoc/org/mockito/Mockito.html

링크에 있는 글대로 작성 해 보면

        stubVoid(mockWarManager).toThrow(new WarPackgingException()).on().packaging();

이렇게 됩니다.

"누가 뭘 던 진다 뭐 할 때."

새로운 형태로 작서한 코드는 다음과 같습니다.
       
        doThrow(new WarPackgingException()).when(mockWarManager).packaging();

"이걸 던진 다. 누가 뭐 할 때"

후자가 조금 더 짧죠.

ps: 매녈 좀 업데이트 해주시지 말입니다. 스프링은 매녈이 소스 코드를 앞서 간다는데...
신고
top

TAG Mockito

JUnit Max 자동 실행 여부 설정하기

Good Tools : 2009.05.12 19:57


도대체 이 기능이 있다고는 하는데, 어딨는지 몰라서 못쓰고 있었네요. 단위 테스트면 뭐 계속 돌아가도 상관이 없는데, 통합 테스트도 완전히 웹 서버까지 띄워서 테스트를 하고 있는데, 이걸 계속 JM이 돌리겠다고 아둥 바둥 하다가 에러를 뱉어 내길래 답답하던 참이었는데 사부님한테 물어봐서 알아냈네요. ㅋㅋㅋ

진작 물어볼 걸...



신고
top

TAG JUnitMax

Maven Embedder 사용해서 자바 코드로 메이븐 Phase 또는 Goal 실행하기

Good Tools : 2009.05.12 16:03


참조: http://maven.apache.org/guides/mini/guide-embedding-m2.html
http://repo1.maven.org/maven2/org/apache/maven/maven-embedder/

메이븐 pom.xml에 의존성을 추가해 줍니다. 엄청 많은 transitive 의존성들이 추가되기 때문에 조금 오래 걸릴 겁니다.

        <!-- maven emberdder -->
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-embedder</artifactId>
            <version>3.0-alpha-2</version>
        </dependency>

이 녀석 하나가 끌고 오는 것만 15개입니다. 따라서 총 16개의 라이브러리를 추가한 겁니다. @_@ 사용하는 방법은 다른 것들은 다 기본 값을 사용하도록 하고, ClassLoader를 설정한 configuration을 만들어서 MavenEmbedder를 만들고, 실행할 phase나 goal들을 MavenExecutionRequest에 담고 execute를 하면 Result를 받을 수 있습니다.

        Configuration configuration = new DefaultConfiguration()
            .setClassLoader(Thread.currentThread().getContextClassLoader());

        ConfigurationValidationResult validationResult = MavenEmbedder
                .validateConfiguration(configuration);

        if (validationResult.isValid()) {
                MavenEmbedder embedder = new MavenEmbedder(configuration);
                MavenExecutionRequest request = new DefaultMavenExecutionRequest();
                request.setGoals(Arrays.asList(new String[] { "package", "cargo:start" }));
                MavenExecutionResult result = embedder.execute(request);
                if (result.hasExceptions()) {
            ...
                }         
        } else {
            ...
        }

이런 식이죠. 이렇게 하지 않고, 그냥 콘솔 명령어를 호출하도록

Runtime rt = Runtime.getRuntime();
Process p = rt.exec("/apps/apache-maven-2.0.10/bin/mvn.bat package");

이렇게 짤 수도 있지만, 이렇게 하면 메이븐이 돌다가 에러 난 상황에 적절한 대처를 하기가 어렵기 때문에 위와 같이 다소 장황한 방법을 사용했습니다.

신고
top


Cargo의 TomcatManager

Good Tools : 2009.05.12 14:36


아파치 톰캣 매니저를 랩핑한 녀석인데 아주 편리합니다.

TomcatManager manager;
manager = new TomcatManager(new URL("http://localhost:8080/manager/"));
manager.deploy("/springsprout", new URL("file:target/springsprout.war"), true);
manager.undeploy("/springsprout");

이런식으로 사용할 수 있습니다.

이슈 1.

Cargo와 관련 된 것이 아니지만, 한 가지 이슈 사항은 undeploy를 했을 때 해당 webapp에서 path에 해당하는 폴더가 지워지지 않으면 그 다음에 같은 폴더로 deploy를 하면, 톰캣은 제대로 배포가 됐다고 생각을 하는데, 실제로는 그렇치 않습니다. 접속해보면 404가 뜨죠.

derby.jar 파일이 지워지지 않고 lib폴더에 남아있는 경우였는데, deploy할 때 무슨 이유에서든가 webapp 밑을 이 파일만은 유독 지워지지 않고 남아서 이 다음 deploy를 방해하고 있었습니다. @_@ 필요도 없는 라이브러리였는데 들어가서 말썽을 부리더군요.

이슈 2.

두 번째는 Cargo에서 제공하는 TomcatManager말고 여러 Deployer들이 있는데, 그 녀석들을 사용하여 deploy는 할 수 있었지만, 그 외의 메서드 redeploy(), undeploy() 등은 Not Supported 예외를 발생시킵니다. 메이븐으로 연동하였을 때도 마찬가지로 cargo:undeploy 등은 not support 에러가 나고 제대로 동작하지 않았습니다. 물론 제가 뭔가 잘못했을 수도 있습니다. @_@ 하지만, TomcatManager 설정이 Deployer 보다 더 간단하고 잘 동작하기 때문에 다시 Deployer를 시도해보진 않을 것 같습니다.


신고
top


JGit로 push 성공 기념샷.

Good Tools : 2009.05.11 01:04


재일이형 제보로 알게된 기트 허브 이클립스 플러그인을 설치할까 하다가 그림을 보니까 JGit랑 거의 흡사하길래 그냥 JGit에 머물기로 했습니다. 위 링크에 보이는 그림 대로 push to를 해봤더니 되네요. 이전에는 어찌해야 할지 몰라서 제대로 못 썼는데 이젠 좀 쓸만하네요.ㅋㅋ

commit, push to, fetch from 메뉴에 단축키만 지정해 두면 웬만한 SVN, CVS 플러그인 부럽지 않게 사용할 수 있을 것 같습니다.

팁으로 SVN, CVS에 비해 히스토리 정보 참조가 엄청나게 빠르다는 겁니다. 그도 그럴 것이 저장소가 로컬에 있으니깐 필요한 히스토리 정보 로딩이 SVN이나 CVS에 비해 훨씬 빠른 것 같습니다. 물론 뭐 네트워크 사정에 따라 조금씩 차이는 있겠지만요..ㅋ




신고
top

TAG JGit, 기트

통합 테스트 분리와 메이븐 관련 참조 할 글

Good Tools : 2009.05.11 00:53


http://docs.codehaus.org/display/MAVENUSER/Maven+and+Integration+Testing

http://docs.codehaus.org/display/MAVEN/Creating+a+Maven+Integration+Test

http://wiki.rodcoffin.com/index.php?title=Maven_Integration_Testing

이 중에서 마지막 글이 지금 봄싹 프로젝트 상태에 가장 적합한 내용인 듯...

통합 테스트를 별도의 프로젝트로 분리할 것인가 말 건인가.. 고민이로세~
신고
top


Cargo 메이븐 플러그인 설정하기

Good Tools : 2009.05.11 00:36


참조: http://cargo.codehaus.org/Maven2+plugin

상당히 간단하지만, 그 결과는 그다지 간단하지 않은 것 같습니다. 일단 설정은 이렇게 했습니다.

            <plugin>
                <groupId>org.codehaus.cargo</groupId>
                <artifactId>cargo-maven2-plugin</artifactId>
                <configuration>
                    <container>
                        <containerId>tomcat6x</containerId>
                        <home>/apps/apache-tomcat-6.0.18</home>
                    </container>
                </configuration>
            </plugin>

이렇게 하고, cargo:start 골을 실행하면 톰캣 서버를 메이븐에서 실행할 수 있습니다. mvn cargo:start 이런식으로요.

테스트 진행은 다음 순서대로 할 겁니다.

WAR 파일 패키징 -> cargo를 사용하여 톰캣 서버 실행 -> 웹 (통합) 테스트 -> cargo를 사용한 톰캣 서버 정지

이 것을 그대로 메이븐 골로 옮겨 적으면 다음과 같습니다.

mvn package cargo:start test cargo:stop

그러나 이건 예상대로 동작하지 않습니다. 일단, 단위 테스트와 통합 테스트가 분리되어야 합니다. 단위 테스트를 실행하는데 굳이 카고를 이용하여 테스트 서버를 실행할 필요는 없기 때문이죠.

두 번째로 cargo:start를 실행하는 순간, 해당 커맨드 창은 이용할 수가 없습니다. 서버 로그가 뜨고 Ctrl+C를 눌러 서버 실행을 멈추기 전까지는 해당 커맨드 창이 먹통이나 다릅없습니다. 또 다른 콘솔을 띄우고 그 곳에서 테스트를 진행 한 다음 cargo:stop으로 서버 실행을 멈출 수 있습니다.

이 두 가지를 생각해 봤을 때 빌드가 2단으로 구성되어야 할 것 같습니다.

1단에서 할 일은 clean package(이 안에 complie, test 포함) cargo:start
2단에서 할 일은 integration-test, cargo:stop

궁금한 건 이러한 2단 빌드를 제공하는 CI 툴이 있느냐 하는 것과 메이븐으로 이런 구성을 하는 방법입니다. 후자는 금방 찾을 것 같은데 전자는 잘 모르겠네요. 기존 CI 툴의 plan을 잘 짜서 여러 plan끼리 의존성을 주며 실행하도록 할 수 있다면 가능할지도 모르겠고, 아예 하나의 plan으로 이러한 2단 빌드를 구성할 수 있게 해준다면 편리할 것 같습니다.
신고
top







티스토리 툴바