web-dev-qa-db-ja.com

java.lang.IllegalStateException:前のメソッド呼び出しgetMessage( "title")の動作定義がありません

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オブジェクトの作成)。

この場合のテスト方法を教えてください。

ありがとう。

25
user362199

テスト対象のメソッドを呼び出す前に、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);
40
Julien Rentrop

私の場合、戻り値の指定(andReturn(...))の省略が原因でした。 http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html 詳細については。

20
Reda

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());
}
0
Mahdi

これにはさまざまな原因が考えられます(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
}
_
0
lukaswelte