N2 ToolBox(跡地)

跡地です。引っ越しました。http://d.hatena.ne.jp/nosen

AspectJでDbC(サンプル)

2004-07-02 00:25:26 | 開発手法/方法論
今日は、AspectJでDbCを実際にちょろっとやってみたサンプルを紹介したいと思います。サンプルとして簡単なスタックの実装を考えてみました。
以下のようなインターフェースがあるとします。

package sample.dbc;

public interface Stack {
    /**
     * スタックのサイズを返す.
     */
    int size();
    /**
     * スタックに引数のオブジェクトをPushする.
     * @param o Pushするオブジェクト
     */
    void push(Object o);
    /**
     * スタックからオブジェクトをpopする.
     */
    Object pop();
    /**
     * スタックの一番上のオブジェクトを返す.
     */
    Object peek();
}
特に説明する必要も無いですね。
このインターフェースに対するContractをAspectJで記述すると以下のようになります。

package sample.dbc;

import junit.framework.Assert;

public aspect StackContract {
    declare parents: StackContract extends Assert;

    /**
     * Invariant.
     */
    after(Stack s) : !within(StackContract) && target(s) && call(public * Stack.*(..)) {
        assertTrue(s.size() >= 0);
    }

    /**
     * Stack#push.
     */
    void around(Stack s, Object o) : target(s) && args(o) && call(public void Stack.push(Object)) {
        //@pre
        assertNotNull(o);

        //@post
        int oldsize = s.size();
        proceed(s, o);
        assertEquals(oldsize + 1, s.size());
        assertSame(o, s.peek());

    }

    /**
     * Stack#pop.
     */
    Object around(Stack s) : target(s) && call(public void pop()) {
        //@post
        int oldsize = s.size();
        Object oldpeek = s.peek();
        Object rv = proceed(s);
        if(oldsize > 0) {
            assertSame(oldpeek, rv);
            assertEquals(oldsize - 1, s.size());
        } else {
            assertNull(rv);
            assertEquals(0, s.size());
        }
        return rv;
    }
}

事前条件、事後条件のチェックをJUnitのAssertクラスを使って行っています。ですから、このアスペクトをWeavingしてテストすれば、JUnitのテストケースにはアサーションのコードを一切書かなくて良くなります。
JUnitでは一般的に一つ一つの入力データに対する具体的な結果を検証するのに対し、DbCでは一般的なルールとして記述するので、記述自体の難易度はDbCの方が難しいです。しかし、クラスの仕様としての明解さ、厳密さはこちらの方が上だと思います。

よく言われるJUnitのメリットの一つに、テストケースからクラスの使い方が分かる、というのがあります。しかし、テストケースからクラスの使い方を知る、という作業は、具体的な入力値と出力値から一般的な仕様を頭の中でリバースエンジニアリングする作業だと思います。DbCにおいては、記述されるのは仕様そのものなので、より直截なアプローチだと思います。

次回は、Stackの実装とJUnitテストケースを紹介します。