본문 바로가기
아직 카테고리 미정

TDD로 XUnit 만들어 내기 - 1

by simplify-len 2021. 2. 25.

Photo by Roman Synkevych on Unsplash

Java 로 XUnit 프레임워크를 잘 만들수 있을지 모르겠습니다. 아직까지 TDD에 대한 자신감이 붙지 않았다는 증거겠죠? 

천천히 수련해봅시다.

youtube에 토비님이 Java로 만든 XUnit 이 있지만, 나 스스로 천천히 수련해봅시다.

먼저 요구사항을 나열하면 아래와 같습니다.

1. 테스트 메소드 실행
2. SetUp 메서드 실행
3. TearDown 메서드 실행
4. 테스트 결과 수집

@Test
public void aaaaa() throws Exception {
    WasRun wasRun = new WasRun();
    assertFalse(wasRun.isRun);
    wasRun.run();
    assertTrue(wasRun.isRun);
}

이제는 isRun을 통해 testMethod가 실행될 수 있도록 해봅시다.

@Test
public void create_testmethod() throws Exception {
    WasRun wasRun = new WasRun("testMethod);
    assertFalse(wasRun.isRun);
    wasRun.run();
    assertTrue(wasRun.isRun);
}

//WasRun.class

public void testMethod() {
	this.isRun = true;
}

이런식으로 WasRun 클래스에 testMethod를 만들어주고, 리플렉션으로 이를 실행시킨다. 이때 run을 할 때 실행될 수 있도록 해주어야 한다.

이번에는 setUpMethod를 만들어 봅시다.

테스트 코드를 먼저 만들고 난 뒤, testCase와 wasRun 클래스를 통해서 빠르게 실행될 수 있도록 해줍시다.

    @Test
    void setUpMethod() {
        assertFalse(wasRun.wasSetUp);
        assertFalse(wasRun.isRun);
        wasRun.run();
        assertTrue(wasRun.isRun);
        assertTrue(wasRun.wasSetUp);
    }
public class WasRun extends TestCase {

    public boolean isRun = false;
    public boolean wasSetUp = false;


    public WasRun(String name) {
        super(name);
    }

    public void testMethod() {
        this.isRun = true;
    }
    @Override
    public void setUp(){
        wasSetUp = true;
    }
}
public class TestCase {
    protected final String name;

    public TestCase(String name) {
        this.name = name;
    }
...

    protected void setUp() {

    }
}

 

이렇게 해서 처음에 작성한 테스트 코드를 초록막대로 바꾸는데, 성공했다. 그렇다면 tearDown도 마찬가지의 방법으로 구현할 것인가?

캔트백 책에서는 로그를 활용해 순서를 기억하도록 구현했습니다.

저는 어떻게 구현해볼까 하다가, 일단 한번 똑같이 구현해보는 전략으로 가져가볼까 합니다.

먼저 String 으로 전략을 변경하면 아래와 같습니다.

@Test
public void templateTestMethod() {
	assertEquals(wasRun.log, "");
	wasRun.run();
	assertEquals(wasRun.log, "setUp testMethod tearDown");
}
public class WasRun extends TestCase {

    public String log = "";

    public WasRun(String name) {
        super(name);
    }

    public void testMethod() {
        log += " testMethod";
    }
    @Override
    public void setUp(){
        log = "setUp";
    }
    @Override
    public void tearDown(){
        log += " tearDown";
    }
}

 

그러나, tearDown에는 예외가 발생하더라도 실행되어야 하는 조건이 있었습니다. 이는 예외가 발생하더라도 tearDown이 실행될 수 있도록, 수정하는 것을 말합니다.

@Test
void exceptionTest() {
	wasRun = new WasRun("testMethodWithException");
	wasRun.run();
	assertEquals(wasRun.log, "setUp testMethod tearDown");
}

이렇게 만들어서 예외를 일으켰을 때도 tearDown이 일어나는지 확인합니다. 

public class TestCase {
    ...

    public void run() {
        setUp();
        try {
            Method method = getClass().getMethod(name);
            method.invoke(this);
        } catch (Exception ignored) {
        }
        tearDown();
    }

 	...
}

 

좋아요. 많이 해낸것 같습니다.

1. 테스트 메소드 실행
2. SetUp 메서드 실행
3. TearDown 메서드 실행
4. 테스트 결과 수집

이번에는 테스트 결과 수집까지 하고, 다음 포스트에서 좀 더 응용된 행위를 해볼까합니다.

그럼 계속..!

테스트 결과를 수집하기 위해서 TestResult 라는 객체를 만들고 다음과 같이 실행했습니다.

public class TestCase {

	...
    
    public TestResult run() {
        TestResult result = new TestResult();
        result.testStarted();

        setUp();
        try {
            Method method = getClass().getMethod(name);
            method.invoke(this);
        } catch (Exception ignored) {
            result.testFailed();
        }
        tearDown();

        return result;
    }

	...
}

 

이때 실수한 부분이 테스트 코드를 먼저 보여드렸어야 했는데, 거꾸로 했네요.

테스트 코드먼저 보여드리면 아래와 같습니다.

    @Test
    void testResult() {
        wasRun = new WasRun("testMethod");
        TestResult result = wasRun.run();
        assertEquals("1 run, 0 failed", result.getSummary());
    }

    @Test
    void testResult_formatting_test() {
        TestResult testResult = new TestResult();
        testResult.testStarted();
        testResult.testFailed();
        assertEquals("1 run, 1 failed", testResult.getSummary());
    }

    @Test
    void testResult_With_failRun()  {
        wasRun = new WasRun("testMethodWithException");
        TestResult result = wasRun.run();
        assertEquals("1 run, 1 failed", result.getSummary());
    }

 

위에서부터 하나씩 처리하면서 코드가 만들어졌습니다.

하면서 계속 잊어버리게 되는건 TDD라는 것에 대해서, 그 절차를 계속 헷갈려하는 제 모습이였습니다.

댓글