Whiteship's Note


TDDBE 2부 xUnit 실습

모하니?/Reading : 2008.09.08 08:36


소스코드

TDDBE - xUnit 18장.
TDDBE - xUnit 19장 (2)
TDDBE - xUnit 20장
TDDBE - xUnit 21장
TDDBE - xUnit 22장
TDDBE - xUnit 23장

스크린캐스트

TDDBE - xUnit 1 (Screen Casting) (4)
TDDBE - xUnit 2 (Screen Casting) (6)
TDDBE - xUnit 3 (Screen Casting) (2)
TDDBE - xUnit 4
TDDBE - xUnit 5
TDDBE - xUnit 6

즐.감. 하시길..
top

TAG TDDBE, xUnit

Write a comment.


TDDBE - xUnit 6



top

Write a comment.


TDDBE - xUnit 5



top

Write a comment.


TDDBE - xUnit 4



top

Write a comment.


TDDBE - xUnit 3 (Screen Casting)





TDDBE 20장을 실습했습니다.

ToDO
- WasRun에서 플래그 대신 로그 메시지로 확인한다.
- 메소드 호출 뒤에는 tearDown()을 호출한다.
top

  1. Favicon of http://ryys1993.tistory.com BlogIcon 윤희한 2008.09.05 15:45 PERM. MOD/DEL REPLY

    고생하셨습니다. 정말 파워블로거세요.. 즐겁게 보았습니다.

    좋은컨텐츠를 제작해주셔서 감사합니다...

    Favicon of http://whiteship.me BlogIcon 기선 2008.09.05 17:05 PERM MOD/DEL

    그런가요.ㅎㅎ 취미 생활이에요.

Write a comment.


TDDBE - xUnit 2 (Screen Casting)





TDDBE 19장을 실습했습니다.

ToDo
-실행 전에 setUp() 메소드를 호출한다.

이 작업을 TDD로 구현했습니다. 물론 책을 따라서..ㅋㅋ
top

  1. Favicon of http://ryys1993.tistory.com BlogIcon 윤희한 2008.09.05 09:53 PERM. MOD/DEL REPLY

    선리플 후감상 ^^;; 잘 보겠습니다..

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.05 09:55 신고 PERM MOD/DEL

    넹. 피드백좀 주세요. :)

    예를 들어.. 위에서는 모든 테스트 케이스를 별도의 객체로 생성을 했는데, 그것에 대해서 어떻게 생각하시는지 듣고 싶습니다.

    성능 VS 테스트케이스 독립. 어떻게 생각하세요?

  2. Favicon of http://ryys1993.tistory.com BlogIcon 윤희한 2008.09.05 12:42 PERM. MOD/DEL REPLY

    음.. 개인적으로는 객체를 따로따로 만들어서 얻을수 있는 이점이 뭐가있을까.. 없지 않을까..

    생각하거든요.. 될수있으면

    객체는 한번만 만들고.. 만들어진 객체를 이용해서 여러 메소드를

    테스트하는게 더 좋을거같다고 생각합니다.

    TestCaseTest tct = new TestCaseTest();

    tct.run("testRunning";);

    이런식으로 run 메소드에 인자를 넘겨서 처리하는게 객체를

    여러개 만들지 않고 성능에 좀더 도움이 될거같아서요

    음.. 제가 정말 몰라서 그러는데.. 테스트 케이스를 독립시켜서.. 얻을수있는 이점이 모가있을까요??

    제가 너무 당연한걸 다시 질문하는걸까요 ㅜ.ㅜ..

    도움이 되어드리질 못하고있네요 ㅜ.ㅜ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.05 12:47 신고 PERM MOD/DEL

    TDDBE 책에 보시면 간략하게 나와있습니다. 테스트끼리 종속되는 현상을 막으려는 의도로 그렇게 설계했습니다.

    A라는 클래스에 a, b, c라는 테슽 메소드가 있는데, b, c가 돌다가 a 가 사용하는 어떤 값을 건드려서 a 테스트가 깨지게 되는 그런 걸 막으려구요. 테스트 케이스 isolation을 시킨겁니다.

    좀 더 자세한 내용은 http://www.martinfowler.com/bliki/JunitNewInstance.html 여기 있다고 하네요.

    밥먹고 와서 읽어봐야겠습니다.

  3. Favicon of http://ryys1993.tistory.com BlogIcon 윤희한 2008.09.05 15:43 PERM. MOD/DEL REPLY

    우와 대단합니다. 정말 즐겁게 읽어보았습니다. 영어가 많이 미천하여 -_-;; (윽.. ㅜ.ㅜ)

    100프로 다 이해한건 아니지만 그래도 쉬운문장으로 쓰여있는부분이 많아서. 내용은

    이해할수있었네요 ^^;;..

    개발자는 영어 필수라는말이 요근래 맘에 와 닿네요..

    Favicon of http://whiteship.me BlogIcon 기선 2008.09.05 17:06 PERM MOD/DEL

    아음 전 하루 종일 모니터 봤더니 좀 어지럽네요; 출력해서 봐야겠어요.

Write a comment.


TDDBE - xUnit 1 (Screen Casting)





TDDBE 2부 xUnit 18장을 실습한 스크린 캐스팅입니다. 이번 장에서 리팩터링 할 것이 많아서 어제 밤에 저기까지 밖에 못 찍었습니다. 분량이 17분인데, mov파일로 축출하는데 시간이 좀 걸려서요; 오늘 밤에는 두 챕터를 더 찍어볼 수 있을 것 같습니다.

거럼 즐감하세요~
top

  1. Favicon of http://architect.tistory.com BlogIcon 짱가 2008.09.04 09:22 PERM. MOD/DEL REPLY

    햐~~ 쉴틈없는 활동 정말 부럽습니다~~~

    p.s.
    스크린 캐스팅이 좀 독특하네요.. ^^
    뭘로 찍었나요?

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.09.04 09:47 PERM MOD/DEL

    맥용 애플리케이션 ScreenFlow를 사용합니다. 기능이 다양한데, 제가 주로 사용한 건 몇 개 안 됩니다. ㅋㅋ

    http://www.flip4mac.com/screenflow.htm

  2. Favicon of http://ryys1993.tistory.com BlogIcon 윤희한 2008.09.04 14:47 PERM. MOD/DEL REPLY

    흐흐흐 잘봤습니다.. assert 사용할 생각을 아예 안했었는데.. 앞으로 자주 사용하겠습니다.

    자주자주 올려주세요 ^^;;

    P.S 목소리 멋지시네요 ^^.... 점점 중독되네요 ^^....

    Favicon of http://whiteship.me BlogIcon 기선 2008.09.04 15:37 PERM MOD/DEL

    캬캬캬. 네. assert 좋습니다. 오늘 저녁에도 가서 녹화하고 내일 올리겠습니다.

Write a comment.


TDDBE - xUnit 23장

모하니?/Coding : 2008.09.01 20:37


드디어 마지막이군요.

ToDo
테스트 여러 개 실행하기

여러 개 테스트를 한 번에 묶어서 실행합니다. 테스트 코드를 실행하던 메인 메소드를 보고 그 중복을 제거하려는 시도에서 비롯된 거 같습니다.

new TestCaseTest("testTemplateMethod").run().summary();
new TestCaseTest("testResult").run().summary();
new TestCaseTest("testFailedResultFormatting").run().summary();
new TestCaseTest("testFailedResult").run().summary();


바로 이 코드를

        TestSuite suite = new TestSuite();
        suite.add(new TestCaseTest("testTemplateMethod"));
        suite.add(new TestCaseTest("testResult"));
        suite.add(new TestCaseTest("testFailedResultFormatting"));
        suite.add(new TestCaseTest("testFailedResult"));
        suite.add(new TestCaseTest("testSuite"));
        TestResult result = new TestResult();
        suite.run(result);
        System.out.println(result.summary());

이렇게 바꿀 겁니다.

그래서 일단 testSuite이라는 테스트 클래스를 작성합니다.
    public void testSuite(){
        TestSuite suite = new TestSuite();
        suite.add(new WasRun("testMethod"));
        suite.add(new WasRun("testBrokenMethod"));
        TestResult result = new TestResult();
        suite.run(result);
        assert result.summary().equals("2 run, 1 failed");
    }

이 클래스는 Composite 패턴을 구현할 생각이라고 합니다. 따라서 TestSuite에 있는 run()과 TestCase()에 있는 run() 메소드는 똑 같은 모양을 해야합니다. 그러다 보니, run() -> run(TestResult)로 설계상의 변화를 줍니다. 그 결과 이미 기존에 존재하는 코드를 수정해야 하는 일이 생겼습니다. 하지만, 테스트 코드가 있었기 때문에 매우 안전하게 변화를 줄 수 있었습니다. 시간도 그만큼 단축이 되는거겠죠.

간단에 TDD의 달콤함을 다시 맛 볼 수 있었던 좋은 시간이었습니다. 이제는 JUnit 1.0 코드를 볼 차례로군요.. 그건 내일;;

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

OSAF 검색 폼 태그 파일 완성  (0) 2008.09.25
Principle of least astonishment  (0) 2008.09.24
How to Design a Good API & Why it Matters  (0) 2008.09.24
delete 요청 처리 컨트롤러 코드 고민  (0) 2008.09.22
@Resource 활용 팁  (6) 2008.09.08
TDDBE - xUnit 23장  (0) 2008.09.01
TDDBE - xUnit 22장  (0) 2008.09.01
TDDBE - xUnit 21장  (0) 2008.09.01
TDDBE - xUnit 20장  (0) 2008.09.01
TDDBE - xUnit 19장  (2) 2008.09.01
TDDBE - xUnit 18장.  (0) 2008.09.01
top

TAG TDD, xUnit

Write a comment.


TDDBE - xUnit 22장

모하니?/Coding : 2008.09.01 20:30


ToDo
실패한 테스트 보고하기

TestResult에서 실패한 테스트 갯수를 세는 메소드 부터 테스트합니다.

    public void testFailedResultFormatting(){
        TestResult result = new TestResult();
        result.testStarted();
        result.testFailed();
        assert result.summary().equals("1 run, 1 failed");
    }

TestResult의 메소드가 갯수를 잘 세고 있는지 확인합니다. 구현은 간단합니다.

public class TestResult {

    int runCount;
    int failedCount;
   
    public void testStarted(){
        this.runCount += 1;
    }

    public void testFailed() {
        this.failedCount += 1;
    }

    public String summary() {
        return runCount + " run, " + failedCount + " failed";
    }

}

그리고 이제 실패하는 테스트 결과를 확인하는 테스트를 작성합니다.

    public void testFailedResult(){
        test = new WasRun("testBrokenMethod");
        TestResult result = test.run();
        assert result.summary().equals("1 run, 1 failed");
    }

총. 1개를 실행했는데, 1개가 실패한 겁니다. 일단, WasRun 클래스에 예외를 발생시키는(실패하는) 테스트를 추가합니다.

    public void testBrokenMethod() throws RuntimeException  {
        throw new RuntimeException("예외 발생하는  테스트");
    }

그리고 TestCase의 run() 메소드에서 예외가 발생할 때마다 TestResult에 처음에 만들어 둔 testFailed()를 호출합니다.

        try {
            Method method = this.getClass().getMethod(methodName, null);
            method.invoke(this, null);
        } catch (InvocationTargetException e) {
            result.testFailed();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

예외를 잡는 부분에 대해서 조금 고민을 했는데, InvocationTargetExcepion만 따로 잡고, 나머진 일단 덩어리로 처리해버렸습니다. 어차피 세세하게 분리를 해놔도 각각의 catch 블럭에서 전부 throw new Runtime(e); 으로 구현할꺼기 때문에, 저렇게 덩어리로 잡아버렸습니다.


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

Principle of least astonishment  (0) 2008.09.24
How to Design a Good API & Why it Matters  (0) 2008.09.24
delete 요청 처리 컨트롤러 코드 고민  (0) 2008.09.22
@Resource 활용 팁  (6) 2008.09.08
TDDBE - xUnit 23장  (0) 2008.09.01
TDDBE - xUnit 22장  (0) 2008.09.01
TDDBE - xUnit 21장  (0) 2008.09.01
TDDBE - xUnit 20장  (0) 2008.09.01
TDDBE - xUnit 19장  (2) 2008.09.01
TDDBE - xUnit 18장.  (0) 2008.09.01
static inner class를 Spring에 bean으로 등록하기  (2) 2008.08.21
top

TAG TDD, xUnit

Write a comment.


TDDBE - xUnit 21장

모하니?/Coding : 2008.09.01 20:19


ToDO
테스트 결과 출력하기

테스트 중에서도 잘 실행하고 종료된 상황을 테스트 합니다.

public class TestCaseTest extends TestCase {

    private WasRun test;

    public TestCaseTest(String methodName) {
        super(methodName);
    }
   
    public void testTemplateMethod(){
        test = new WasRun("testMethod");
        test.run();
        assert test.log.equals("setUp testMethod tearDown ");
    }
   
    public void testResult(){
        test = new WasRun("testMethod");
        TestResult result = test.run();
        assert result.summary().equals("1 run, 0 failed");
    }
   
    public static void main(String[] args) {
        new TestCaseTest("testTemplateMethod").run();
        new TestCaseTest("testResult").run();
    }
}

모든 테스트 케이스 마다 매번 결과를 확인할 수 있도록 설계를 합니다. 그래서 run() 메소드에서 실행 결과를 나타내는 TestResult를 반환 하도록 합니다.

 public class TestCase {
   
    String methodName;

    public TestCase(String methodName) {
        this.methodName = methodName;
    }
   
    public TestResult run() {
        TestResult result = new TestResult();
        result.testStarted();
        setUp();
        try {
            Method method = this.getClass().getMethod(methodName, null);
            method.invoke(this, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        tearDown();
        return result;
    }

    protected void tearDown() {}

    protected void setUp() {}
}

물론 첨부터 저렇게 구현하진 않았습니다. 처음에는 그냥 return new TestResult()를 했다가. TestResult에서 설계가 들어갑니다. 결과값을 testStarted()라는 걸 호출 해서 속에 있는 카운터를 증가시키는 구조로 말이죠.

public class TestResult {

    int run;
   
    public void testStarted(){
        this.run += 1;
    }

    public String summary() {
        return run + " run, 0 failed";
    }

}

얘도 첨엔 이렇게 안 생겼었고, 처음엔 상수를 반환했습니다. 그랬다가 일단 앞에 있는 실행 갯수만을 변수화 했고, 위의 설계 결정에 따라 구현을 변경한 겁니다.

리팩터링과, 설계, 그리고 TDD의 관계를 생각하게 만드는 챕터였습니다.
top

TAG TDD, xUnit

Write a comment.


TDDBE - xUnit 20장

모하니?/Coding : 2008.09.01 20:13


ToDo
나중에 tearDown 호출하기.

이 작업을 하기 전에 일단 이전까지 사용하던 flag 방식은 실행 순서를 못 잡기 때문에..이 작업을 잠시 미루고

ToDo
WasRun에 로그 문자열 남기기.

이 작업을 먼저 합니다. 모든 작업을 마치고 나면...
public class TestCaseTest extends TestCase {

    public TestCaseTest(String methodName) {
        super(methodName);
    }
   
    public void testTemplateMethod(){
        WasRun test = new WasRun("testMethod");
        test.run();
        assert test.log.equals("setUp testMethod tearDown ");
    }
   
    public static void main(String[] args) {
        new TestCaseTest("testTemplateMethod").run();
    }
}

테스트 코드가 줄어듭니다. 두둥.. 과정을 보여드리지 못해 아쉽네요.

public class WasRun extends TestCase {

    String log;
   
    public WasRun(String methodName) {
        super(methodName);
    }
   
    public void testMethod() {
        log += "testMethod ";
    }
   
    @Override
    protected void setUp() {
        log = "setUp ";
    }
   
    @Override
    protected void tearDown() {
        log += "tearDown ";
    }

}

WasRun에서는 flag를 없애고 로그를 남기는 방식으로 바껴서.. 역시 코드가 또 줄어들었습니다.

public class TestCase {
   
    String methodName;

    public TestCase(String methodName) {
        this.methodName = methodName;
    }
   
    public void run() {
        setUp();
        try {
            Method method = this.getClass().getMethod(methodName, null);
            method.invoke(this, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        tearDown();
    }

    protected void tearDown() {}

    protected void setUp() {}
}

끝..

top

TAG TDD, xUnit

Write a comment.


TDDBE - xUnit 19장

모하니?/Coding : 2008.09.01 16:42


이번에는 "먼저 setUp() 메소드를 호출한다."를 구현했습니다.

public class TestCaseTest extends TestCase {

    WasRun test;
   
    public TestCaseTest(String methodName) {
        super(methodName);
    }
   
    protected void setUp() {
        test = new WasRun("testMethod");
    }
   
    public void testRunning(){
        test.run();
        assert test.wasRun == true;
    }
   
    public void testSetUp(){
        test.run();
        assert test.wasSetUp == true;
    }
   
    public static void main(String[] args) {
        new TestCaseTest("testRunning").run();
        new TestCaseTest("testSetUp").run();
    }
}

테스트 클래스는 이미 setUp()을 반영했지만, 사실 setUp()을 반영하기 전에 구현을 마치고, 리팩터링 하면서 방금 구현한 setUp()을 사용해서 테스트 클래스까지 간단하게 리팩터링을 했습니다.

import java.lang.reflect.Method;

public class TestCase {
   
    String methodName;

    public TestCase(String methodName) {
        this.methodName = methodName;
    }
   
    public void run() {
        setUp();
        try {
            Method method = this.getClass().getMethod(methodName, null);
            method.invoke(this, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected void setUp() {}
}

Template Method 패턴을 사용해서, 하위 클래스에서 setUp()을 맘대로 구현할 수 있도록.. 했구요. run()에 워크 플로우를 정의했죠.

public class WasRun extends TestCase {

    boolean wasRun;
    boolean wasSetUp;
   
    public WasRun(String methodName) {
        super(methodName);
    }
   
    public void testMethod() {
        wasRun = true;
    }
   
    @Override
    protected void setUp() {
        wasRun = false;
        wasSetUp = true;
    }

}

WasRun에서도 역시 방금 구현한 setUp()을 사용해서 생성자를 좀 더 간단하게 했습니다.

'이번 장의 핵심 내용은 테스트 케이스들 간의 의존성을 없애기'였습니다. 지금처럼 매번 별도의 인스턴스를 만들기 때문에, 전역 변수를 사용하는 테스트가 아닌 이상 테스트 케이스들끼리 의존할 가능성은 거의 없게 됩니다.

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

@Resource 활용 팁  (6) 2008.09.08
TDDBE - xUnit 23장  (0) 2008.09.01
TDDBE - xUnit 22장  (0) 2008.09.01
TDDBE - xUnit 21장  (0) 2008.09.01
TDDBE - xUnit 20장  (0) 2008.09.01
TDDBE - xUnit 19장  (2) 2008.09.01
TDDBE - xUnit 18장.  (0) 2008.09.01
static inner class를 Spring에 bean으로 등록하기  (2) 2008.08.21
국내 최초 OSGi 기반 애플리케이션 프레임워크 OSAF 1.5 - 멀지 않았다.  (2) 2008.08.12
Mockito - 아규먼트 Matcher  (0) 2008.08.12
JavaMail - 첨부파일 읽기  (0) 2008.08.07
top

TAG 19장, TDD, xUnit
  1. Favicon of http://toby.epril.com BlogIcon 토비 2008.09.01 17:54 PERM. MOD/DEL REPLY

    최소한의 구현을 하는 것까지 해서(TDDBE 책에 나오는 정도) 스크린캐슷으로 만들어보지 그래.
    DW에 공개해도 좋겠는데.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.01 18:32 신고 PERM MOD/DEL

    넹. 재밌는데요 이거. ㅎㅎ 파이썬 코드라서 나름대로 자바 코드로 다시 구성하는 재미가 쏠쏠하네요. :)

Write a comment.


TDDBE - xUnit 18장.

모하니?/Coding : 2008.09.01 16:00


파이썬으로 되어있는 예제라서, TDD(테스트 주도 개발) 책을 읽으면서 그냥 넘어갔던 부분인데.. 도무지 그냥 넘어갈 만한 부분이 아닌거 같아서 자바로 코딩해보기로 했습니다. 파이썬으로 코딩해도 되겠지만, 저는 자바로.. 그래서 18장을 우선 코딩해봤습니다.

캬~ 재밌네요.

public class TestCaseTest extends TestCase {

    public TestCaseTest(String methodName) {
        super(methodName);
    }
   
    public void testRunning(){
        WasRun test = new WasRun("testMethod");
        assert test.wasRun == false;
        test.run();
        assert test.wasRun == true;
    }
   
    public static void main(String[] args) {
        new TestCaseTest("testRunning").run();
    }
}

위에 있는 TestCase는 JUnit에 있는게 아닙니다. 직접 구현한 클래스입니다. 구현체는 다음과 같습니다.

public class TestCase {
   
    String methodName;

    public TestCase(String methodName) {
        this.methodName = methodName;
    }
   
    public void run() {
        try {
            Method method = this.getClass().getMethod(methodName, null);
            method.invoke(this, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

이것을 상속받은 WasRun은 다음과 같습니다.

public class WasRun extends TestCase {

    boolean wasRun;
   
    public WasRun(String methodName) {
        super(methodName);
        wasRun = false;
    }

    public void testMethod() {
        wasRun = true;
    }

}

TestCase와 WasRun은 원래 하나의 클래스였는데, 책임이 두 개가 되자(하나는 실행됐는지 여부를 확인하는 플래스, 하나는 동적으로 메소드를 실행하는 역할) 그 즉시 리팩터링을 합니다. 상위 클래스를 만들고 그 쪽으로 Pull Up Field, Pull Up Method를 합니다.

코드도.. 정말 딱 테스트가 통과할 만큼만 만들고, 테스트 성공 시킨 다음에는 상수를 변수로 바꾸는 리팩터링 부터 시작해서, 위에서 언급한 리팩터링까지.. 쫘르륵...

캬.. 역시 그냥 읽는 것 보다 한 번 해보는거랑은 차이가 큽니다.
top

TAG TDD, xUnit

Write a comment.