UnitTestの記述にEasyMock(バージョン2.4)とTestNGを使用しています。
次のシナリオがあり、クラス階層の定義方法を変更できません。
ClassAを拡張しているClassBをテストしています。
ClassBは次のようになります
public class ClassB extends ClassA {
public ClassB()
{
super("title");
}
@Override
public String getDisplayName()
{
return ClientMessages.getMessages("ClassB.title");
}
}
ClassAコード
public abstract class ClassA {
private String title;
public ClassA(String title)
{
this.title = ClientMessages.getMessages(title);
}
public String getDisplayName()
{
return this.title;
}
}
ClientMessagesクラスコード
public class ClientMessages {
private static MessageResourse messageResourse;
public ClientMessages(MessageResourse messageResourse)
{
this.messageResourse = messageResourse;
}
public static String getMessages(String code)
{
return messageResourse.getMessage(code);
}
}
MessageResourseクラスコード
public class MessageResourse {
public String getMessage(String code)
{
return code;
}
}
ClassBのテスト
import static org.easymock.classextension.EasyMock.createMock;
import org.easymock.classextension.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ClassBTest
{
private MessageResourse mockMessageResourse = createMock(MessageResourse.class);
private ClassB classToTest;
private ClientMessages clientMessages;
@Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.replay(mockMessageResourse);
}
}
このテストを実行すると、次の例外が発生します。
Java.lang.IllegalStateException:前のメソッド呼び出しgetMessage( "title")の動作定義がありません
私が見つけたものをデバッグしている間、それはモックメソッドコールを考慮していませんmockMessageResourse.getMessage( "ClassB.title")としてコンストラクターから呼び出されています(ClassBオブジェクトの作成)。
この場合のテスト方法を教えてください。
ありがとう。
テスト対象のメソッドを呼び出す前に、EasyMock.replay(mock)
を呼び出す必要があります。テスト対象のメソッドを呼び出した後、EasyMock.verify(mock)
を呼び出して、モックが呼び出されたことを確認できます。
次に、2回呼び出すため、「title」引数を使用して別のexpect
呼び出しを追加する必要があります。
コード:
EasyMock.expect(mockMessageResourse.getMessage("title")).andReturn("title");
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.verify(mockMessageResourse);
私の場合、戻り値の指定(andReturn(...))の省略が原因でした。 http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html 詳細については。
replay
呼び出しの後にexpect
を呼び出し、beforeを使用する必要があります。この場合、テストを次のように変更する必要があります。
@Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
}
これにはさまざまな原因が考えられます(someMock
は、この回答のモックされたオブジェクトの名前です)。一方では、経由でコールを期待する必要があるかもしれません
_expect(someMock.someMethod(anyObject()).andReturn("some-object");
_
Reda's answer のように。 Julien Rentrop's answer でわかるように、モックを使用する前にreplay(someMock)
を呼び出すのを忘れたこともあります。
ここで言及しなかった最後の可能性は、テストの前に別の場所でモックを使用し、reset(someMock)
を介してモックをリセットするのを忘れたことです。
これは、次のような複数の単体テストがある場合に発生する可能性があります。
_private Object a = EasyMock.createMock(Object.class);
@Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
@Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
_
モックaは次のテストで使用される前にリセットされなかったため、これはIllegalStateExceptionで1つのテストで失敗します。それを解決するには、次のことを実行できます。
_private Object a = EasyMock.createMock(Object.class);
@Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
@Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
@After
public void tearDown() throws Exception {
reset(a); // reset the mock after each test
}
_