【Java】JUnit4でSpring3とJMock2を使う方法 その2 | さすらいびとの徒然漂流記

さすらいびとの徒然漂流記

ふらふら漂流するさすらいびとのように,色々な話題についてお気楽極楽,徒然なるままに…

以前は親クラスで使えるようにする方法 を書いたんだけど,

「それってやっぱり違うよな」って思ったので,

今度はRunnerを拡張する方法を紹介.



手順としては


  • JMockアサーションを呼び出す独自Runnerの作成
  • JMockアサーションの独自Statementの作成

まずは,Spring TestのSpringJUnit4ClassRunner

拡張したクラスを作成する.


public class JMockSpring3JUnit4ClassRunner

extends SpringJUnit4ClassRunner {


private Field mockeryField; // Mockeryインスタンスのフィールド


public JMockSpring3JUnit4ClassRunner(Class<?> clazz)

throws InitializationError {
super(clazz);

// Mockeryインスタンスを探してアクセス可能にする
mockeryField = findMockeryField(clazz);
mockeryField.setAccessible(true);
}


private static Field findMockeryField(Class<?> clazz)

throws InitializationError {

// JMock.classのソースからそのままパクリ

// Mockeryインスタンスのフィールドを探して返す
}


@Override
protected Statement withAfters(

FrameworkMethod frameworkMethod,

Object testInstance,

Statement statement) {

// まずは親クラスの処理を呼び出してStatementチェーンを作る
statement = super.withAfters(frameworkMethod, testInstance, statement);

// 今回のアサーションStatementをチェーンに追加する
return new VerifyJMockExpectations(testInstance, statement,

this.getExpectedException(frameworkMethod), this.mockeryField);
}

}


続いて,Runnerクラスで使っているJMockアサーション用の

Statementクラスを作成する.


public class VerifyJMockExpectations extends Statement {
private final Object test;
private final Statement next;
private final Class<? extends Throwable> expectedException;
private final Field mockeryField;


public VerifyJMockExpectations(Object testInstance,
Statement stmt,
Class<? extends Throwable> expectedException,
Field mockeryField) {
this.test = testInstance;
this.next = stmt;
this.expectedException = expectedException;
this.mockeryField = mockeryField;
}


@Override
public void evaluate() throws Throwable {
try {

// 次のチェーンを評価する
this.next.evaluate();

// 以下のコードも基本的にはJMock.classから流用

// 取得したMockeryインスタンスをアサートする
this.mockeryOf(this.test).assertIsSatisfied();
} catch (InvocationTargetException e) {
Throwable actual = e.getTargetException();
Class<? extends Throwable> expectedType = this.expectedException;

if (expectedType != null && expectedType.isInstance(actual)) {

// 例外が投げられるテストの場合の手当て
this.mockeryOf(this.test).assertIsSatisfied();
}

throw e;
}
}


private Mockery mockeryOf(Object test) {

// JMock.classのソースからそのままパクリ

// Mockeryインスタンスを取得する

}
}


これで普通にRunnerを@RunWithにわたせばOK.


@RunWith(JMockSpring3JUnit4ClassRunner.class)
@ContextConfiguration
public class RunnerTest {
private Mockery context; // モックコンテキストの定義も忘れずに!


// 以下,JMock+SpringTestのテストコード
}


やっぱりこっちの方がスマートな感じだね.


2010/05/02 Updated

evaluateメソッドのコードに転記ミスがあったので修正.

ついでに説明コメントを一応追加してみた.