
リリース2.2 の文書(2006年4月16日)
© 2001-2006 OFFIS, Tammo Freese.
EasyMock 2 は与えられたインターフェースに対するモックオブジェクトを生成し、使用する 簡単な方法を提供します。EasyMock 2はMIT licenseの下で利用可能です.
モックオブジェクトはドメインコードの振る舞いの一部をシミュレートし、 それらが定義された通りに使用されているかどうかをチェックします。 ドメインクラスは、自分と協調して動作するクラスの振る舞いをモックオブジェクト によってシミュレートすることによって、単独でテストすることが可能になります。
モックオブジェクトを書き、保守する作業は退屈で、ミスの起こりやすいものです。 EasyMock2はモックオブジェクトを動的に生成するので、それを書く必要も、 コードを生成する必要もありません。
EasyMockはデフォルトではインターフェースに対するモックオブジェクト生成のみを サポートします。クラスに対するモックオブジェクトを生成したい人のための 拡張はEasyMockのホームページから利用できます。
easymock2.2.zip)。 zipファイルには
easymock2.2ディレクトリが含まれます。このディレクトリにある
EasyMockのjarファイル(easymock.jar)をクラスパスに追加してください。
EasyMockのテストを実行するには、クラスパスにtests.zipとJUnit4を
追加し、'java org.easymock.tests.AllTests'を起動してください。
EasyMockのソースコードはzipファイルsrc.zipに格納されています。
ソフトウェアシステムの多くの部分は、独立して動作するのではなく、 仕事を遂行するために他の部分と協調して動作しています。 多くの場合、それらの協調して動作する部分は信頼できるので、ユニットテスト時にそれらのことを気にする必要は ありませんが、もし、気にする必要がある場合は、モックオブジェクトは単一の部分を単独でテスト する助けになります。モックオブジェクトはテスト対象となる部分と協調して動作する部分を置き換えるのです。
以下の例はインタフェースCollaboratorの使用法を示しています。
package org.easymock.samples;
public interface Collaborator {
void documentAdded(String title);
void documentChanged(String title);
void documentRemoved(String title);
byte voteForRemoval(String title);
byte[] voteForRemovals(String[] title);
}
このインターフェースの実装はClassUnderTestという名前のクラス
と協調して動作します(この場合はリスナとして動作します)。
public class ClassUnderTest {
// ...
public void addListener(Collaborator listener) {
// ...
}
public void addDocument(String title, byte[] document) {
// ...
}
public boolean removeDocument(String title) {
// ...
}
public boolean removeDocuments(String[] titles) {
// ...
}
}
二つのクラスのコードはsamples.zipの中の
org.easymock.samplesの中にあります。
以下の例は、テスティングフレームワーク JUnitに関する知識を前提にしています。 ここで示されるテストはJUnit バージョン3.8.1を使用していますが、JUnit 4やTestNGも同じように 使えるでしょう。
EasyMockパッケージの機能を理解するために、テストケースを作成して
それをいじくってみましょう。
samples.zipにはこのテストの修正されたバージョンが含まれています。
最初のテストでは、存在しないドキュメントの削除が、リスナとして動作しているCollaboratorクラスに
通知されないことをチェックします。
以下はモックオブジェクトの定義を含まないテストです。
package org.easymock.samples;
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;
protected void setUp() {
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}
public void testRemoveNonExistingDocument() {
// This call should not lead to any notification
// of the Mock Object:
classUnderTest.removeDocument("Does not exist");
}
}
EasyMock2を使った多くのテストでは、org.easymock.EasyMockのメソッドの
静的インポートのみが必要です。これはEasyMockに置ける唯一の公開された、
非推奨でないクラスです。
import static org.easymock.EasyMock.*;
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;
}
モックオブジェクトを取得するために、以下の処理が必要です。
以下に最初の例を示します。
protected void setUp() {
mock = createMock(Collaborator.class); // 1
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}
public void testRemoveNonExistingDocument() {
// 2 (we do not expect anything)
replay(mock); // 3
classUnderTest.removeDocument("Does not exist");
}
ステップ3で活性化された後、mockはインタフェースCollaborator
に対するモックオブジェクトとなります。
この例では、インタフェース Collaborator に対するどんなメソッド呼出しもないことが期待されます。
従って、もしクラスClassUnderTestをインタフェースCollaboratorのメソッドのどれかを
呼び出すように変更すれば、モックオブジェクトはAssertionErrorをスローします。
java.lang.AssertionError:
Unexpected method call documentRemoved("Does not exist"):
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentRemoved(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74)
at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33)
at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24)
...
二番めのテストを書いてみましょう。ドキュメントがテスト対象クラスに追加された場合、 mock.documentAdded()メソッドがドキュメントのタイトルを引数として呼び出されることが期待されます。
public void testAddDocument() {
mock.documentAdded("New Document"); // 2
replay(mock); // 3
classUnderTest.addDocument("New Document", new byte[0]);
}
このように、記録状態の時(つまりreplayを呼ぶ前)には
モックオブジェクトはモックオブジェクト的に振る舞うのではなく、
メソッド呼出しを記録します。replayを呼んだ後は
普通のモックオブジェクトとして動作し、期待されたメソッド呼出しが
実際に行われるかどうかをチェックします。
classUnderTest.addDocument("New Document", new byte[0])が
期待されるメソッドを間違った引数とともに呼んだ場合、モックオブジェクトは
以下のようにAssertionErrorをスローします。
java.lang.AssertionError:
Unexpected method call documentAdded("Wrong title"):
documentAdded("New Document"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentAdded(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
...
間違ったメソッド呼出しに対応する、期待していたメソッド呼出しと共に、 まだ実行されていないすべての期待されたメソッド呼出しが表示されます(この場合では存在しませんが)。 メソッド呼出しの回数が多すぎる場合は、以下のようなエラーが発生します。
java.lang.AssertionError:
Unexpected method call documentAdded("New Document"):
documentAdded("New Document"): expected: 1, actual: 1 (+1)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentAdded(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30)
...
今までのところまだ扱っていないタイプのエラーが1種類あります。指定した振る舞いが
実際には実行されていない場合です。現在のテストは
モックオブジェクトに対して一回もメソッド呼出しを行わなかったとしても
成功していまいます。指定された振る舞いが実際に実行されたかどうか検証するには、
以下のようにverify(mock)を呼び出さなければなりません。
public void testAddDocument() {
mock.documentAdded("New Document"); // 2
replay(mock); // 3
classUnderTest.addDocument("New Document", new byte[0]);
verify(mock);
}
この場合、もしモックオブジェクトに対するメソッド呼出しが行われなかったら、 以下のように例外が出力されます。
java.lang.AssertionError:
Expectation failure on verify:
documentAdded("New Document"): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
at org.easymock.EasyMock.verify(EasyMock.java:536)
at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31)
...
例外メッセージは期待どおりに実行されていない全てのメソッド呼出しを一覧表示します。
今までのテストでは、単一のメソッド呼出しのみを考慮してきました。
次のテストでは既に同じタイトルのドキュメントを重複して追加したとき、
mock.documentChanged()メソッドが正しい引数で
呼び出されるかどうかをチェックします。
念のため、これを3回チェックすることにします。
(これはあくまでサンプルですよ ;-))
public void testAddAndChangeDocument() {
mock.documentAdded("Document");
mock.documentChanged("Document");
mock.documentChanged("Document");
mock.documentChanged("Document");
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
verify(mock);
}
mock.documentChanged("Document")の繰り返しを避けるため、
EasyMockはショートカットを用意しています。
expectLastCall()から返されるオブジェクトに対してtimes(int times)
メソッドを呼び出すことによって、呼出し回数を指定することが出来ます。
そのコードは以下のようになります。
public void testAddAndChangeDocument() { mock.documentAdded("Document");
mock.documentChanged("Document");
expectLastCall().times(3);
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
classUnderTest.addDocument("Document", new byte[0]);
verify(mock);
}
メソッド呼出しの回数が多すぎる場合、その旨を伝える例外がスローされます。 テストは指定した回数を超えた最初のメソッド呼出しがおこなわれた時、すぐに失敗します。
java.lang.AssertionError:
Unexpected method call documentChanged("Document"):
documentChanged("Document"): expected: 3, actual: 3 (+1)
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.documentChanged(Unknown Source)
at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67)
at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26)
at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
...
メソッドの呼出し回数が少な過ぎるとき、verify(mock)はAssertionErrorをスローします。
java.lang.AssertionError:
Expectation failure on verify:
documentChanged("Document"): expected: 3, actual: 2
at org.easymock.internal.MocksControl.verify(MocksControl.java:70)
at org.easymock.EasyMock.verify(EasyMock.java:536)
at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43)
...
戻り値を指定するには、期待される呼出しをexpect(T value)でラップし、
戻り値をexpect(T value)が返すオブジェクトの
andReturn(Object returnValue)メソッドによって指定します。
例として、ドキュメント削除のワークフローをチェックすることにします。
ClassUnderTestはドキュメントが削除されようとしているとき
(=removeDocument(String title)が呼び出されたとき)、
全ての協働者(=Collaboratorインタフェースの実装)に本当にそのドキュメントを削除して良いかどうか、
byte voteForRemoval(String title)メソッドを呼び出すことによって尋ねます。
戻り値が正の値だった場合は削除に賛成となります。全ての戻り値の合計が正の値だった場合、ドキュメント
は削除され、全ての協働者(=Collaboratorインタフェース)のdocumentRemoved(String title)
メソッドが呼び出されます。
public void testVoteForRemoval() {
mock.documentAdded("Document"); // expect document addition
// expect to be asked to vote for document removal, and vote for it
expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
mock.documentRemoved("Document"); // expect document removal
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
assertTrue(classUnderTest.removeDocument("Document"));
verify(mock);
}
public void testVoteAgainstRemoval() {
mock.documentAdded("Document"); // expect document addition
// expect to be asked to vote for document removal, and vote against it
expect(mock.voteForRemoval("Document")).andReturn((byte) -42);
replay(mock);
classUnderTest.addDocument("Document", new byte[0]);
assertFalse(classUnderTest.removeDocument("Document"));
verify(mock);
}
戻り値の型はコンパイル時にチェックされます。例えば、 以下のコードは与えられた戻り値の型とメソッドの戻り値の型が一致していないので コンパイルされません。
expect(mock.voteForRemoval("Document")).andReturn("wrong type");
戻り値設定用のオブジェクトを取得するのには、expect(T value)を
呼び出す代わりにexpectLastCall()を使用することも出来ます。
つまり、以下のコードの代わりに
expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
次のように指定することもできるのです。
mock.voteForRemoval("Document");
expectLastCall().andReturn((byte) 42);
コンパイル時に型チェックが出来ないので、このような型指定の仕方は 一行が長くなりすぎるときに限定すべきです。
例外(より正確にはThrowable)がスローされるように指定するには、
expectLastCall() と expect(T value) が返すオブジェクトの
andThrow(Throwable throwable) メソッドを使用します。
このメソッドは記録状態の時に、例外をスローしたいメソッドの呼出しをモックオブジェクトに対して
行ったあとに呼び出さなければなりません。
チェック対象外の例外(つまり、RuntimeException, Error
およびそれらのサブクラス)をスローすることもできます。チェック対象例外は、その例外が
実際に対象メソッドのthrows句に指定されている場合のみ指定できます。
前もって期待される戻り値や例外を指定するのではなく、
実際のメソッド呼出しの実行時に戻り値や例外を生成したい時もあるでしょう。
EasyMock2.2からは、expectLastCall()とexpect(T value)
が返すオブジェクトはandAnswer(IAnswer answer)メソッドを提供します。
このメソッドの引数にIAnswerインタフェースの実装を渡すことで、
戻り値や例外を生成することが出来ます。
IAnswer コールバックの内部で、モックに渡された引数は
EasyMock.getCurrentArguments() を通じて利用できます。
これを利用すると、パラメータの順序変更のようなリファクタリングによってテストが
壊れる可能性があるので注意が必要です。
times, andReturn, および andThrow
メソッドを繋げて使用することによって、
一つのメソッドに対する振る舞いを変更することも可能です。
例えば、次の例ではvoteForRemoval("Document")を以下のように
定義しています。
RuntimeExceptionをスローする。
expect(mock.voteForRemoval("Document"))
.andReturn((byte) 42).times(3)
.andThrow(new RuntimeException(), 4)
.andReturn((byte) -42);
呼出し回数のチェックに幅を持たせるために、times(int count)
の代わりに使える、以下のメソッドが用意されています。
times(int min, int max)min と max の間の回数呼出しが行われることを期待します。atLeastOnce()anyTimes()
呼出し回数が指定されていない場合は、1回呼出しが行われることが期待されます。
もしこのことを明示的に宣言したい場合は、
once()またはtimes(1)を使用できます。
EasyMock.createMock()から返されるモックオブジェクトは、
メソッドの呼出し順序をチェックしません。
メソッドの呼出し順序をチェックする厳密なモックオブジェクトを作りたいときは、
EasyMock.createStrictMock()を使用してください。
厳密なモックオブジェクトに対して期待しないメソッドが呼び出された場合、
例外メッセージとしてその時点で期待されていたメソッド呼出しに続き、
最初に期待に反した実際のメソッド呼出しが表示されます。
verify(mock)は全てのまだ実行されていない期待されるメソッド呼出しを
表示します。
一部のメソッド呼出しだけ呼出し順序のチェックを有効にしたモックオブジェクトを作成する
必要があることがあります。記録フェーズでcheckOrder(mock, true)を呼び出すことによって、
呼出し順序チェックを有効化し、checkOrder(mock, false)を呼び出すことで無効化
することができます。
厳密なモックオブジェクトと普通のモックオブジェクトの間には2つの違いがあります。
実際のメソッド呼出しを期待されるメソッド呼出しと照合するとき、参照型の
引数はデフォルトではequals()メソッドを使用して比較されます。
このことが問題になることがあります。
例えば、以下のような期待について考えてみましょう。
String[] documents = new String[] { "Document 1", "Document 2" };
expect(mock.voteForRemovals(documents)).andReturn(42);
もしメソッドが同じ内容を持つ別の配列を引数として呼び出されたら、
equals()メソッドは二つの配列をオブジェクトIDによって
比較するので、例外が発生してしまいます。
java.lang.AssertionError:
Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e):
voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0
documentRemoved("Document 1"): expected: 1, actual: 0
documentRemoved("Document 2"): expected: 1, actual: 0
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44)
at $Proxy0.voteForRemovals(Unknown Source)
at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88)
at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48)
at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83)
...
この呼出しに対しては配列の等価性のみが必要であることを指定するために、
EasyMockクラスから静的インポートされたaryEqメソッドが
使用できます。
String[] documents = new String[] { "Document 1", "Document 2" };
expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
(訳注:aryEqメソッドを呼び出すことによってその引数に対してArgument Matcherが設定されます) もし、メソッド呼出しのなかで Argument Matcher を使用したいなら、全ての引数に対して matcherを指定しなければなりません。
一連の前もって定義された Argument Matcherが利用できます。
eq(X value)anyBoolean(), anyByte(), anyChar(), anyDouble(), anyFloat(), anyInt(), anyLong(), anyObject(), anyShort()eq(X value, X delta)float と doubleに対して利用できます。aryEq(X value)Arrays.equals()を使用し、指定された値が実際の値と等しいかどうか判定します。プリミティブ型とオブジェクトの配列に対して利用できます。isNull()notNull()same(X value)isA(Class clazz)lt(X value), leq(X value), geq(X value), gt(X value)startsWith(String prefix), contains(String substring), endsWith(String suffix)matches(String regex), find(String regex)and(X first, X second)first と second の両方にマッチするときマッチします。全てのプリミティブ型とオブジェクトに対して利用できます。or(X first, X second)first and secondのいずれかにマッチするときにマッチします。全てのプリミティブ型とオブジェクトに対して利用できます。not(X value)valueにマッチしないときにマッチします。独自のArgument Matcherを定義したくなるときがあります。 例えば、エラーメッセージと例外の型の両方が等しいときマッチするArgument Matcherが必要だったとしましょう。 それは以下のように使用できるべきです。
IllegalStateException e = new IllegalStateException("Operation not allowed.")
expect(mock.logThrowable(eqException(e))).andReturn(true);
これを実現するためには2つのステップが必要です。1つめは新しいArgument Matcherを定義すること、
2つめはスタティクメソッドeqExceptionを宣言することです。
新しいArgument Matcherを定義するには、インタフェースorg.easymock.IArgumentMatcherを実装します。
このインタフェースは2つのメソッドを含みます。matches(Object actual)は実際の引数が指定された
引数にマッチするかどうかチェックします。appendTo(StringBuffer buffer)はArgument Matcherの
文字列表現を与えられたStringBufferに追加します。実装はわかりやすいものです。
import org.easymock.IArgumentMatcher;
public class ThrowableEquals implements IArgumentMatcher {
private Throwable expected;
public ThrowableEquals(Throwable expected) {
this.expected = expected;
}
public boolean matches(Object actual) {
if (!(actual instanceof Throwable)) {
return false;
}
String actualMessage = ((Throwable) actual).getMessage();
return expected.getClass().equals(actual.getClass())
&& expected.getMessage().equals(actualMessage);
}
public void appendTo(StringBuffer buffer) {
buffer.append("eqException(");
buffer.append(expected.getClass().getName());
buffer.append(" with message \"");
buffer.append(expected.getMessage());
buffer.append("\"")");
}
}
eqExceptionメソッドは指定されたThrowableを使ってこのArgument Matcherを生成し、
reportMatcher(IArgumentMatcher matcher)メソッドによってEasyMockにそのArgumentMatcherの
ことを伝え、メソッド呼出しの中でこのメソッドを使えるように戻り値を返さなければなりません。
(多くの場合、0, null または falseを返します。)
最初の試作品は次のようになります。
public static Throwable eqException(Throwable in) {
EasyMock.reportMatcher(new ThrowableEquals(in));
return null;
}
しかしながら、これはlogThrowableメソッドが、Throwableを引数として受け取る
既に例示された使い方をされて、RuntimeExceptionのようなより特化された
例外が要求されない場合のみうまく動きます。後者の場合、我々のコードサンプルはコンパイルできなく
なるでしょう(以下を参照)。
IllegalStateException e = new IllegalStateException("Operation not allowed.")
expect(mock.logThrowable(eqException(e))).andReturn(true);
この場合、Java 5.0が助けになります。eqExceptionの引数と戻り値をThrowable
として定義する代わりに、Throwableを拡張するジェネリック型を定義するのです。
public static <T extends Throwable> T eqException(T in) {
reportMatcher(new ThrowableEquals(in));
return null;
}
モックオブジェクトはreset(mock)メソッドによってリセットされます。
モックオブジェクトをあるメソッド呼出しに応答させたいが、何回呼び出されたか、いつ呼び出されたか、それとも
全く呼び出されなかったのかはチェックしたくない場合があります。
このスタブ的振る舞いはandStubReturn(Object value)、メソッドを使用して定義できます。
andStubThrow(Throwable throwable)、 andStubAnswer(IAnswer
および asStub()の各メソッドを使用して定義できます。
以下のコードはモックオブジェクトをvoteForRemoval("Document")に対しては42を1回返し、
その他の引数に対しては-1を返すように設定します。
expect(mock.voteForRemoval("Document")).andReturn(42);
expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
createMock()が返すモックオブジェクトのデフォルトの振る舞いは全てのメソッドが予期しない
メソッド呼出しに対してAssertionErrorをスローする、というものです。
もし、全てのメソッド呼出しを許可し、適切な空の値(0、 null または false)を返す
「上品な」モックオブジェクトを好むのであれば、代わりにcreateNiceMock()を使ってください。
Objectの3つのメソッド(equals()、
hashCode() および toString())
の振る舞いは、EasyMockが作ったモックオブジェクトについては
たとえそれがMockObjectが実装しているインターフェースの一部だったとしても
変更できません。
今まではEasyMockクラスのスタティックメソッドによって設定される単一のモックオブジェクトのみを見てきました。
しかし、実はそれらのスタティックメソッドの多くは、裏でモックオブジェクトを制御する単一のオブジェクトに処理を委譲している
のです。この制御オブジェクトはIMocksControlインタフェースを実装したオブジェクトです。
従って、以下のコードの代わりに、
IMyInterface mock = createStrictMock(IMyInterface.class);
replay(mock);
verify(mock);
reset(mock);
以下の同等のコードを使用することができます。
IMocksControl ctrl = createStrictControl();
IMyInterface mock = ctrl.createMock(IMyInterface.class);
ctrl.replay();
ctrl.verify();
ctrl.reset();
IMocksControlによって複数のモックオブジェクトを生成することが可能になり、複数のモックにまたがってメソッド呼出しの順序を
チェックすることが可能になります。例えば、IMyInterfaceインタフェースに対して2つのモックオブジェクトをセットアップ
するとしましょう。そしてまず、mock1.a()とmock2.a()を順番に、次にmock1.c()
とmock2.c()を任意の回数、最後にmock2.b() と mock1.b()を順に実行することを
期待します。この設定を行うコードは以下のようになります。
IMocksControl ctrl = createStrictControl();
IMyInterface mock1 = ctrl.createMock(IMyInterface.class);
IMyInterface mock2 = ctrl.createMock(IMyInterface.class);
mock1.a();
mock2.a();
ctrl.checkOrder(false);
mock1.c();
expectLastCall().anyTimes();
mock2.c();
expectLastCall().anyTimes();
ctrl.checkOrder(true);
mock2.b();
mock1.b();
ctrl.replay();
EasyMock 2 は互換性レイヤーを含んでいるため、Java1.5用の EasyMock 1.2を使ったテストは
変更なしに動作するでしょう。既知の唯一の違いは、エラーが発生したときに現れます。
エラーメッセージとスタックトレースはすこし変更され、エラーはJUnitのAssertionFailedError
の代わりにJavaのAssertionErrorとして報告されるようになりました。
EasyMock2.1 は EasyMock 2.2 では複雑過ぎるということで削除された
コールバック機能を含んでます。EasyMock 2.2からはIAnswerインタフェースが
コールバック機能を提供しています。
EasyMock 1.0は OFFIS のTammo Freeseによって 開発されました。EasyMockの開発は、他の開発者や企業の貢献を可能にするため、 現在 SourceForgeでホスティングされています。
フィードバックをくださった方々に感謝します。 Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr, Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, Rex Madden, David McIntosh, Karsten Menne, Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Richard Scott, Joel Shellman, Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht, Frank Westphal, Chad Woolley, Bernd Worsch, 他、多くの方々。
新しいバージョンについてはEasyMock のホームページを 確認し、バグレポートや提案を EasyMock Yahoo!Group. まで送ってください。EasyMock Yahoo!Groupに参加したいならメッセージを easymock-subscribe@yahoogroups.com まで送ってください。
EasyMock Version 2.2 (2006年4月17日)
2.1からの変更:
andAnswer(IAnswer answer) と andStubAnswer(IAnswer answer)に
よって実行時に生成できるようになりました。
callback(Runnable runnable) は削除されました。代わりに、
andAnswer(IAnswer answer) と andStubAnswer(IAnswer answer)
を使うようにしてください。
replay(), verify() および reset() は複数のモックオブジェクトを
引数として受け付けることができるようになりました。
2.0からの変更:
EasyMock.getCurrentArguments()を通して
コールバックから利用できるようになりました。
1.2からの変更:
junit.framework.AssertionFailedErrorの代わりにjava.lang.AssertionErrorを
スローするようになりました。従って、テスティングフレームワークに依存しなくなり、JUnit 3.8.x, JUnit 4および
TestNGが使用できるようになりました。