web-dev-qa-db-ja.com

パッケージ保護されたメソッドをスタブしようとするときに、実際のメソッド実装を呼び出すMockitoモック

Mockito 1.8.5を使用してメソッドをスタブしようとしていますが、そうすると実際のメソッド実装(parm値として ""を使用)が呼び出され、例外がスローされます。

package background.internal; //located in trunk/tests/Java/background/internal

public class MoveStepTest {

    @Test
    public void testMoveUpdate() {
        final String returnValue = "value";
        final FileAttachmentContainer file = mock(FileAttachmentContainer.class);
        doReturn(returnValue).when(file).moveAttachment(anyString(), anyString(), anyString());
        //this also fails
        //when(file.moveAttachment(anyString(), anyString(), anyString())).thenReturn(returnValue);

        final AttachmentMoveStep move = new AttachmentMoveStep(file);
        final Action moveResult = move.advance(1, mock(Context.class));
        assertEquals(Action.done, moveResult);
    }
}

私がモックしようとしている方法はこのように見えます。最終的なメソッドやクラスはありません。

package background.internal; //located in trunk/src/background/internal


   public class FileAttachmentContainer {
        String moveAttachment(final String arg1, final String arg2, final String arg3) 
                throws CustomException {
            ...
        }

        String getPersistedValue(final Context context) {
           ...     
        }
    }

そして、モックを渡すクラスは次のようになります。

package background.internal; //located in trunk/src/background/internal
public class AttachmentMoveStep {

    private final FileAttachmentContainer file;

    public AttachmentMoveStep(final FileAttachmentContainer file) {
        this.file = file;        
    }

    public Action advance(final double acceleration, final Context context) {
        try {
            final String attachmentValue = this.file.getPersistedValue(context);
            final String entryId = this.file.moveAttachment(attachmentValue, "attachment", context.getUserName());

            //do some other stuff with entryId
        } catch (CustomException e) {
            e.log(context);
        }    
        return Action.done;
    }
}

実際の実装が呼び出される原因は何ですか?どのように防ぐことができますか?

27
Jake Walsh

モックしているメソッドは、Mockitoコードからアクセスできません。

テストコードとテスト対象のコードは同じパッケージにあるため、コンパイラによりモックをそのように設定できますが、実行時にMockitoライブラリはmoveAttachmentにアクセスしようとしなければなりませんが、あなたの場合。これは、Mockitoでは bug または 既知の制限 のように見えます(実際に、ほとんどの場合サポートしています)。

最も簡単なことは、moveAttachmentをパブリックメソッドにすることです。それが選択肢でない場合は、まずそれをモックするかどうかを最初に質問します。実際のメソッドが呼び出されるとどうなりますか?

最後のオプションは、 PowerMock を使用してmoveAttachmentメソッドをプライベートメソッドとして扱い、そのようにモックすることです。

21
jhericks

受け入れられた回答に同意しません。

環境についてもっと詳しく説明する必要があると思います。問題を再現できません。 Mavenプロジェクトで次のコードを記述します。

package background.internal; //located in src/main/Java

public class FileAttachmentContainer {
    String moveAttachment(String arg1, String arg2, String arg3) {
        throw new IllegalStateException();
    }

    String getPersistedValue(Context context) {
        throw new IllegalStateException();
    }
}

そして

package background.internal;

public class AttachmentMoveStep {

    private FileAttachmentContainer file;

    public AttachmentMoveStep(FileAttachmentContainer file) {
        this.file = file;
    }

    public Action advance(double acceleration, Context context) {
        String attachmentValue = file.getPersistedValue(context);
        file.moveAttachment(attachmentValue, "attachment", context.getUserName());
        return Action.done;
    }
}

そして、次のテストパス

package background.internal; //located in src/test/Java

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import org.junit.Test;

public class MoveStepTest {

    @Test
    public void testMoveUpdate() {
        String returnValue = "value";
        FileAttachmentContainer file = mock(FileAttachmentContainer.class);
        doReturn(returnValue).when(file).moveAttachment(anyString(), anyString(), anyString());
        //this also works
        //when(file.moveAttachment(anyString(), anyString(), anyString())).thenReturn(returnValue);

        AttachmentMoveStep move = new AttachmentMoveStep(file);
        Action moveResult = move.advance(1, mock(Context.class));
        assertEquals(Action.done, moveResult);
    }
}

私のプロジェクトは次の依存関係を使用します。

  • jdk1.7.0_05
  • junit-4.10.jar
  • mockito-all-1.9.0.jar
  • javassist-3.16.1-GA.jar
  • objenesis-1.2.jar
  • hamcrest-core-1.1.jar
0
gontard