튜토리얼이 매우 잘 만들어져 있습니다. 다음은 튜토리얼 목차인데, 성격급한 분들은 조금 버거울 수 있는 분량입니다.

개인적으로는 `Test Coverage` 분량이 적지 않지만 매우 심혈을 기울여 만든 것으로 보입니다.

image from: https://flask.palletsprojects.com/en/2.3.x/tutorial/

gradle 빌드로 테스트케이스를 실행할 수 있습니다.


src/main 이 아닌 src/test/java/hello 폴더에 GreeterTest.java 클래스를 만듭니다. 

파일 첨부합니다.

gradle-start.zip

.

├── build.gradle

├── gradle

│   └── wrapper

│       ├── gradle-wrapper.jar

│       └── gradle-wrapper.properties

├── gradlew

├── gradlew.bat

└── src

    ├── main

    │   └── java

    │       └── hello

    │           ├── Greeter.java

    │           └── HelloWorld.java

    └── test

        └── java

            └── hello

                └── GreeterTest.java


GreeterTest.java 내용은 다음과 같습니다.

package hello;


import static org.junit.Assert.*;

import static org.hamcrest.CoreMatchers.*;


import org.junit.*;


public class GreeterTest {

    @Test

    public void sayHello() {

        Greeter greeter = new Greeter();

        assertThat(greeter.sayHello(), is("Hello world!"));

    }

}


build.gradle 파일에는 junit.jar 파일을 추가합니다.

apply plugin: 'java'


repositories { mavenCentral() }

dependencies {

  compile "joda-time:joda-time:2.2"

  testCompile "junit:junit:4.11"

}


testCompile로 지정한 jar의 경우 최종 결과물에는 포함되지 않습니다. build 폴더를 보면 reports 폴더가 생기고 test 결과가 있습니다. 

.

├── build

│   ├── classes

│   │   ├── main

│   │   │   └── hello

│   │   │       ├── Greeter.class

│   │   │       └── HelloWorld.class

│   │   └── test

│   │       └── hello

│   │           └── GreeterTest.class

│   ├── dependency-cache

│   ├── libs

│   │   └── gradle-start.jar

│   ├── reports

│   │   └── tests

│   │       ├── base-style.css

│   │       ├── css3-pie-1.0beta3.htc

│   │       ├── hello.GreeterTest.html

│   │       ├── hello.html

│   │       ├── index.html

│   │       ├── report.js

│   │       └── style.css

│   ├── test-results

│   │   ├── TEST-hello.GreeterTest.xml

│   │   └── binary

│   │       └── test

│   │           ├── output.bin

│   │           ├── output.bin.idx

│   │           └── results.bin

│   └── tmp

│       └── jar

│           └── MANIFEST.MF


index.html 파일을 브라우저로 열어보면 다음과 같습니다.

gradle에 대한 권남님의 블로그를 추천합니다.

http://wiki.kwonnam.pe.kr/gradle/java


메일로 온 질문에 답변을 공유합니다.


====

Q:

좋은 강의 감사드립니다.

강의 내용을 정리하면서 몇가지 질문이 생겼습니다.


1. Junit 을 사용할 테스트는 무조건 return 구문과 출력 구문을 만들어야 하나요?

return 값이 void 인 경우는 어떻게 하나요?


2. 예전 책을 보면 tomcat을 컨테이너라고 하고

웹서버와 구분을 합니다. 웹서버 아파치와 구분을 하는데

정확히 웹서버와 was, 컨테이너의 차이를 모르겠습니다.


동적인 페이지를 처리하기위해 was가 필요하다고 하니

was가 웹서버의 역할까지 포함하고 있는 것이라고 생각했는데

was와 웹서버를 같이 사용하는 경우도 있고...개념이 헷갈립니다.


3. Spring에서 service와 controller의 차이가 어떤 것인지 알고 싶습니다.

실제로 서비스에서 하는 행위를 컨트롤러 단에서 해도 상관이 없다고 생각됩니다.


4. Spring과 스트럭쳐를 같이 사용할 이유가 있는지 알고 싶습니다.

처음 공부할 때 두가지를 같이 병행하는데 역시 spring만으로 구현이 가능한 것 같습니다.


마지막으로 가능하다면 강의에 사용하셨던 구글 문서 주소를 다시 알려주셨으면 합니다.

이번에 윈도우 8.1을 써본다고 하다가 그만 즐겨찾기를 지워버리는 실수를 해서....

단순히 업데이트로 생각했다가 많은 자료가 사라져 버렸습니다.

구글 크롬에 북마크는 정리가 끝난 사이트만 관리하다보니 이런 불상사가 생겼네요.


더운 날이 계속되는 여름입니다.

건강관리에 유의하시기 바랍니다.

다시 한번 좋은 강좌와 okjsp에 많은 도움에 감사드립니다.


A:

안녕하세요.

답변 드리겠습니다.


1. void 인 함수의 역할이 무엇인지, 상태값을 변화시킨다면 그리고 그것을 검증해야 한다면, 

테스트를 위해, 상태값을 읽어오는 함수를 통해서 테스트할 수 있을 것입니다.


2. 웹서버는 html, css, js, image들을 서비스하는 아파치 웹서버 (http://httpd.apache.org), 

IIS 등이 있습니다.  WAS는 Web Application Server의 약자이고, JSP/Servlet을 실행할 수 있는

서블릿 컨테이너와 EJB가 실행되는 EJB 컨테이너로 구성되어 있습니다.

초기에는 WAS의 정적인 파일 처리 능력이 낮기 때문에 웹서버와 연결해서 사용했는데, 

(mod_jk, ajp 같은 커넥터류) 요즘은 WAS 자체에서 http 서버의 역할을 감당할 만한 성능이 나와서

단독으로 웹서버의 역할까지 커버하는 경우가 많습니다.


3. 강의 때도 말씀드렸는데, request, response 같은 객체와 분리된 비즈로직이 Service에서 실행됩니다.

저 두 파라미터가 Service에 없다는 것은 Service를 WAS와 분리해서 단독으로 실행할 수 있게 됩니다.

Controller의 역할은 Model과 View를 연결해 준다는 본연의 역할이 있지요.

http://csl.ensm-douai.fr/noury/20 MVC song인데, 동영상과 가사를 함께 생각해보시면 도움이 되실 것입니다.


4. 스트럿츠를 스프링과 연계시키는 이유는 제 생각으로는 당시 스트럿츠로 만들어진 시스템이 많았고,

스트럿츠 개발자들이 많았기 때문이 아닌가 생각됩니다.

지금은 말씀하신대로 스프링MVC로 모두 커버 가능합니다.


감사합니다.


구글문서 주소는 http://bit.ly/eclipse201306 입니다.


테스트 자동화를 위한 것 중에서 브라우저를 통한 테스팅을 자동화 시킨 것 중 추천할 만한 것이 Selenium 입니다. 쉬운 사용법과 Ajax 호출까지 지원되는 등 다양한 테스트를 녹화해서 사용할 수 있습니다. 이에 대한 사용법과 Ant와 Eclipse 에서도 사용하는 법이 소개되어 있습니다.

요약: Selenium은 자동화된 웹 애플리케이션 테스트에 사용하는 테스트 프레임워크입니다. Selenium RC(Selenium Remote Control)에 익숙해지면 다양한 브라우저를 대상으로 웹 애플리케이션을 테스트하여 웹 애플리케이션의 품질이 최상의 상태가 되도록 할 수 있습니다.

http://www.ibm.com/developerworks/kr/library/wa-testweb/index.html


Selenium에 관해서는 오래 알아왔는데 블로그에는 첫 포스팅이군요.


JUnit을 이용한 테스트케이스를 실행한 결과를 api형태의 보고서로 또는 그래픽으로 비주얼하게 보여줄 수 있습니다.

http://www.okjsp.pe.kr/docs/report 에서 확인할 수 있습니다.

아울러 hudson에서도 다른 형태의 리포트가 나옵니다.
우측 상단의 파란색 그래프입니다.

더 자세한 정보도 볼 수 있습니다.

http://www.okjsp.pe.kr:8080/job/okjsp%20site%20build/

아주 오래 미뤄왔던 일을 해내었습니다. 이제 버그 잡아야겠습니다.
이전 포스트에 이어집니다.

junit task를 다음과 같이 변경할 수 있습니다.
    <target name="test" depends="compile">
        <mkdir dir="report/html"/>
        <junit printsummary="on" haltonfailure="on">
            <classpath refid="test.classpath">
            </classpath>
            <formatter type="xml"/>
            <batchtest todir="report">
                <fileset dir="dst">
                    <include name="**/*Test*"/>
                </fileset>
            </batchtest>
        </junit>
    </target>

리포팅 기능을 강화한 설정입니다.
report 폴더에 TEST-*.xml 파일이 생성이 됩니다.
이 파일을 이용해서 다음과 같은 문서를 생성할 수 있습니다.


추가되는  junitreport 코드는 다음과 같습니다. 굵게 표시해 놓았습니다.
    <target name="test" depends="compile">
        <mkdir dir="report/html"/>
        <junit printsummary="on" haltonfailure="on">
            <classpath refid="test.classpath">
            </classpath>
            <formatter type="xml"/>
            <batchtest todir="report">
                <fileset dir="dst">
                    <include name="**/*Test*"/>
                </fileset>
            </batchtest>
        </junit>
        <junitreport todir="report">
            <fileset dir="report">
                <include name="TEST-*.xml"/>
            </fileset>
            <report format="frames" todir="report/html"/>
        </junitreport>
    </target>

이제 남은 작업은 소스와 테스트코드 분리 설정과 그 후에 okjsp사이트에 적용하는 것입니다.
샘플 첨부합니다.

참고서적: 이클립스 프로젝트 필수 유틸리티, 민진우, 이인선 , 한빛미디어, 2009, p251~255

고전적인 자바 클래스의 테스트는 main() 메소드에 값을 찍어보는 코드를 넣어서 콘솔에서 확인합니다. 이클립스에 익숙해진 덕에 JUnit에서 System.out.println() 집어 넣는 것은 초딩같은 습관이라고 생각을 "저만"했었습니다. 하지만, 찍어본다는 것 그리고 그것을 눈으로 확인하는 것은 굉장한 심리적 안정감을 주기는 합니다. 아직 assertEquals() 는 보이지 않는 신뢰가 필요하기 때문이죠.

httpunit의 테스트코드를 보니 재밌는 부분이 있었습니다. 상당히 많은 수의 테스트케이스에 main() 메소드가 있었고, 그 메인메소드는 JUnit을 기반으로 해당 테스트코드를 수행하도록 만들어주는 것이었습니다.


suite() 메소드를 inline 리팩토링하면 junit.textui.TestRunner.run( new TestSuite( EncodingTest.class ));  를 통해서 실행을 합니다. Java Application 으로 실행한 결과는 다음과 같습니다.

..............
Time: 3.813

OK (14 tests)

물론 이 클래스는 JUnit을 통해서도 실행됩니다.

다른 사람의 코드를 읽는 것, 프로그래머 소통의 시작이 아닐까 생각해봅니다.

참고로 HttpUnitTest 클래스의 상속구조입니다. ctrl+T 로 이클립스에서 볼 수 있습니다.


 

최근 TSS에 재밌는 기사가 하나 떴습니다. 테스트케이스가 공식적으로 개발과정에 포함되는지 아니면 비공식적으로 만들어지는지에 관한 조사였습니다. 2006년에 이어서 2년 후인 2008년 설문을 진행했습니다. 데이터는 다음과 같습니다.

Answers 2008 (2006)
Unit testing is not performed: 17% (13%)
Unit testing is informal: 40% (46%)
Unit tests cases are documented: 9% (11%)
Unit tests cases and their executions are documented: 14% (16%)
We use a Test Driven Development approach: 20% (14%)

Participants: 384 (2006: 460)
Ending date: October 2008 (February 2006)
Source: Methods & Tools (http://www.methodsandtools.com/)

TDD 접근법을 사용하는 것은 20%로 증가한 것에 비해 단위테스트에 대한 노력은 오히려 감소했습니다. 그리고 의외인 것은 외국에서도 아직 단위테스트가 보편적이지 않다는 것이었습니다.

오픈소스 프로젝트 하나를 앞서 살펴봤습니다. 여기에는 test라는 테스트케이스를 모아놓은 폴더가 있었습니다. 소스의 양은 얼마나 될까요. httpunit 이라는 단위테스트용 프로젝트이기 때문에 좀 더 많이 있을 거라 예상했습니다.
예상대로 제가 회사에서 만든 테스트코드들과는 비교할 수 없이 많더군요.

요기까지가 패키지 하나에 들어있는 소스 코드들입니다. 이 코드들을 테스트하는 테스트케이스는 다음과 같습니다.
그리 많은 것은 아니지만 대략 1/5 정도 테스트케이스의 클래스들이 있지않나 생각됩니다. 각 테스트케이스 내의 테스트 메소드들이 애플리케이션에 대한 코드 커버리지를 책임지겠지요.

테스트케이스를 모아놓은 것이 테스트스위트입니다. *Suite.java 로 찾아보면 다음과 같은 스위트들이 보입니다.

빌드 스크립트에서도 테스트 관련 배치작업을 찾을 수 있습니다.



test 타겟을 실행해보니 다음과 같은 결과가 나오는군요.
test:
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .....................................F....
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .........................................
     [java] .....................................
     [java] Time: 22.656
     [java] There was 1 failure:
     [java] 1) testCookieAge(com.meterware.httpunit.cookies.CookieTest)junit.framework.AssertionFailedError: cookie2 expiration expected:<1223798608260> but was:<1112124642000>
     [java]  at com.meterware.httpunit.cookies.CookieTest.testCookieAge(CookieTest.java:202)
     ...
     [java]  at com.meterware.httpunit.HttpUnitSuite.main(HttpUnitSuite.java:49)
     [java] FAILURES!!!
     [java] Tests run: 775,  Failures: 1,  Errors: 0
BUILD SUCCESSFUL
Total time: 36 seconds

디버깅을 할 것은 아니지만, 이렇게 테스트케이스를 775가지 이상 갖고 있는 애플리케이션을 관리하는 것은 좀 더 수월하지 않을까 생각됩니다. 작업환경의 차이에서 발생하는 버그도 찾을 수 있고, 코드 변경으로 인한 틀어짐도 놓치지 않기 때문입니다.

읽어주셔서 감사합니다. 알찬 11월 되시길...
앞서 오픈소스를 통해서 소스 저장소에 등록되는 디렉토리 구조를 살펴보았습니다. 그리고 프로젝트 소스를 일괄처리하는 build.xml 도 살짝 들여다 보았습니다. 이클립스 툴을 쓰면 다 되는 작업을 왜 Ant 빌드스크립트를 만들어야하는지 질문을 종종 들어봤습니다. 지속적인 통합 빌드 같이 주기적으로 반복되는 작업이나 단계가 복잡한 작업들은 빌드스크립트가 효과적입니다. 클릭클릭하는 일도 지겨울 때가 있거든요. 이클립스 작업의 자동화가 빌드 스크립트라고 생각하시면 될 것입니다.

지난 번 소스 가져오기(import) 이후로 소스의 빌드 경로를 잡아보려고 합니다. 로컬pc에서 컴파일되나 안되나 확인하는 것이죠. 소스가 패키지에 맞게 제자리에 있어야 할 것이고, 참조하는 jar파일의 경로도 함께 지정해줘야 합니다.

일단 이클립스 자바 프로젝트에서 소스 폴더를 추가합니다. 자바소스가 있는 폴더를 소스폴더라고 합니다. *.java 파일과 *.properties 파일들이 위치합니다. httpunit-1.7 아래 src 폴더가 바로 소스폴더입니다. 그리고 httpunit-1.7 아래 test 라는 곳도 소스 폴더로 추가합니다. src 아래 있는 클래스들을 테스트하는 테스트케이스들의 소스 폴더입니다.

자동 빌드가 일어나면서 에러가 무진장 일어납니다. jar 파일 연결이 안되서 그렇습니다.

왼쪽 패키지 익스플로러에서 프로젝트를 선택하고 Properties 창을 엽니다. 컨텍스트 메뉴에서 제일 아래 Properties 메뉴를 선택하면 됩니다. 단축키는 alt+Enter
Java Build Path 항목을 선택하고 Libraries 탭을 클릭합니다.

우측의 Add JARs... 버튼을 클릭해서 httpunit-1.7/jars 폴더의 *.jar 파일들을 선택합니다.

오호, 에러가 줄기는 했는데, 하나 남았네요. fnfe를 클릭해서 해당 소스를 열어보겠습니다. 흠, 겁을 상실했군요. 에~ 뭐 꼭 고친다는 뜻은 아닙니다. ^^;

소스를 살짝 보니 캐릭터셋 문제로 Roger Lindsj 이름 옆에 이상한 문자가 생긴 것 같네요. 그것 때문에 아랫줄 if라인이 주석 줄로 따라 올라온 듯 합니다.

if 앞에서 엔터로 줄바꿔주니 고쳐졌습니다. ^^; 잠시 우쭐~

Problems 탭에 에러는 싹 사라졌군요. Warnings는 살짝 봐주기로 하죠. ^^;

소스 폴더가 추가된 모습입니다.

작업공간은 에러 없는 코드로 관리되는 것이 개발자 심리에 좋다고 생각을 합니다. ^^;

오픈소스의 좋은 점 중 하나는 제품 개발과정을 볼 수 있다는 것입니다. 소스 프로젝트의 구성을 볼 수 있고, ant나 maven 등의 빌드 구성과 TestCase를 어떻게 만들었는지 확인이 가능합니다.

httpunit이라는 소스포지의 오픈소스를 통해서 그 구성을 살펴보겠습니다.
http://httpunit.sourceforge.net 에 접속합니다.

왼쪽 메뉴 중 Download를 클릭해서 다운로드 받습니다.

파일을 이클립스에서 import 해보겠습니다. httpunit 이라는 이름으로 자바프로젝트를 하나 만듭니다.

프로젝트를 선택하고 컨텍스트 메뉴에서 Import... 를 선택합니다.

ar 이라고 필터란에 입력하면 Archive File 메뉴가 보입니다.

앞서 다운로드 받은 httpunit-1.7.zip 파일을 선택합니다.

폴더 통째로 import를 해왔습니다.

디렉토리의 구성을 잘 살펴볼 필요가 있습니다.
doc : 아마도 html 이나 프로젝트 관련 문서들 원본 등이 있을 것입니다.
examples : httpunit을 이용하는 예제들 디렉토리
jars : 프로젝트 관련 jar 파일 디렉토리
lib : httpunit.jar 산출물 생성 디렉토리
META-INF : jar 압축시 기본 생성 디렉토리
src : java 소스 디렉토리
test : 테스트케이스 디렉토리
build.xml : 프로젝트 빌드를 위한 ant 빌드 스크립트


이러한 구성을 참고로 자신이 진행하는 프로젝트의 소스 및 파일들을 관리하는 것도 좋을 것입니다.

+ Recent posts