Groovyでクロージャを使って例外のテストを局所的にしてみる

id:taediumさんのエントリ

あと気に入ったのは例外のテスト。期待する例外をテストメソッドの属性に書くと、例外をスローするかもしれないスコープが広くなりすぎてしまうですが、デリゲートを使うことでとても局所的にできます。例外を戻してさらにテストすることもできます。

という日本語部分だけみて脊髄反射で書いてみた。


元々のxUnit.netのコードは全然みてないので(デリゲートわからない><)、全く関係ない話かもしれないけど気にしない気にしない。


import junit.framework.AssertionFailedError

class SampleTest extends GroovyTestCase {

    // enhancing GroovyTestCase
    static {
        GroovyTestCase.metaClass.assertThrown = { Class throwable, Closure closure ->
            try {
                closure.call()
            } catch (e) {
                if (!throwable.isInstance(e)) {
                    throw new AssertionFailedError("unexpected exception is thrown. expected: ${throwable}, but: ${e.class}")
                }
                return e
            }
            throw new AssertionFailedError("expected exception was not thrown. expected: ${throwable}")
        }
    }

    // →Green
    void testExpectedException() {
        assertThrown(RuntimeException) {
            throw new RuntimeException("HOGEHOGE")
        }
    }

    // →Green
    void testExpectedException_usingReturnValue() {
        def e = assertThrown(RuntimeException) {
            throw new RuntimeException("HOGEHOGE")
        }
        assert e.message == "HOGEHOGE"
    }

    // →Red: unexpected exception is thrown. expected: class java.lang.RuntimeException, but: class java.io.IOException
    void testUnexpectedException() {
        assertThrown(RuntimeException) {
            throw new IOException("HOGEHOGE")
        }
    }

    // →Red: expected exception was not thrown. expected: class java.lang.RuntimeException
    void testNoException() {
        assertThrown(RuntimeException) {
            // do nothing
        }
    }

}


try-catchや@Test(expected)よりも良いかもしれぬ。


と、こんなの普通に思いつくことだから、もしかしてすでにある?と思って調べてみたら、あったよママン。


↓こんな風に使える。

class SampleTest extends GroovyTestCase {

    void testExpectedException() {
        shouldFail(RuntimeException) {
            throw new RuntimeException("HOGEHOGE")
        }
    }

    void testExpectedException_usingReturnValue() {
        def exceptionMessage = shouldFail(RuntimeException) {
            throw new RuntimeException("HOGEHOGE")
        }
        assert exceptionMessage == "HOGEHOGE"
    }

    void testUnexpectedException() {
        shouldFail(RuntimeException) {
            throw new IOException("HOGEHOGE")
        }
    }

    void testNoException() {
        shouldFail(RuntimeException) {
            // do nothing
        }
    }

}


知らなかった。こんどから使おうっと。