【问题标题】:Mockito mock calling real method implementation when attempting to stub package protected method尝试存根包保护方法时,Mockito 模拟调用真实方法实现
【发布时间】:2014-07-21 23:50:58
【问题描述】:

我正在尝试使用 Mockito 1.8.5 对方法进行存根,但这样做会调用引发异常的真实方法实现(使用 "" 作为参数值)。

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;
    }
}

是什么导致真正的实现被调用,我该如何防止它?

【问题讨论】:

  • 你能添加实际执行测试的代码吗?
  • FileAttachmentContainer 还是方法moveAttachment() 最终? Mockito 无法模拟最终方法。
  • 真的用 anyString() 的值调用 moveAttachment 吗?
  • 你的测试类和FileAttachmentContainer在同一个包里吗?如果没有,它将无法访问moveAttachment
  • 这看起来可能是一个注入问题 - 就像模拟设置正确,但模拟并不是真正在测试中使用的对象。如果您能向我们展示测试的代码和实际正在测试的代码,那将很有帮助。

标签: java mockito


【解决方案1】:

Mockito 代码无法访问您正在模拟的方法。

因为您的测试代码和被测代码在同一个包中,编译器允许您以这种方式设置您的模拟,但在运行时,Mockito 库必须尝试访问 moveAttachment,但它无法正常工作你的情况。这似乎是 Mockito 中的 bugknown limitation,因为它应该支持这种情况,(事实上,在大多数情况下确实支持它)。

最简单的方法是将moveAttachment 设为公共方法。如果这不是一个选项,那么首先要问你是否想模拟它。如果调用真正的方法会发生什么?

最后一个选项是使用PowerMockmoveAttachment 方法视为私有方法并以这种方式模拟它。

【讨论】:

  • 这似乎是问题所在。看起来其他人也遇到过:code.google.com/p/mockito/issues/detail?id=127Thanks
  • 这是不正确的。一般来说,Mockito 可以毫无问题地模拟包私有方法。这个错误似乎是 OSGi/sealed jars 或类似的问题。
  • @Arendv.Reinersdorff,如果这是真的,那么 PowerMock 还能做到吗?如果是这样,我会改变我的答案,以更好地反映其中的“为什么”部分。
  • @jhericks 我不知道 :-( 只是根据错误报告猜测 Jake 问题的原因。抱歉,我现在看到这不是很有帮助。但 Mockito 绝对可以模拟包私有方法,我经常使用。
  • @Arendv.Reinersdorff 我已经编辑了我的答案,希望更准确。我认为我建议的补救措施仍然有效,但我认为它们是“解决方法”,而不是任何用户错误。
【解决方案2】:

我不同意接受的答复。

我认为,您必须提供有关您的环境的更多详细信息。我无法重现您的问题。我在一个 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

【讨论】:

  • 这根本不是答案。它只是说明您无法弄清楚提问者为什么会遇到问题。问题是,“是什么导致调用真正的实现?我该如何防止它?”我回答了“我怎样才能防止它”部分,但只对“造成它的原因”部分进行了猜测。这个答案两者都没有。这个答案只是说它应该工作,你不知道为什么它不工作。
  • @jhericks,你是对的,我不知道为什么,对我来说这是个问题。我认为我们必须追根溯源,找出问题的根本原因。不仅仅是提供一些解决方法。
  • @gontard 你编译成两个单独的罐子了吗?一个用于测试,一个用于实现?
  • @JakeWalsh 是的,它也可以。您能否提供有关您的环境的更多详细信息?你在用osgi,proguard...?
  • @gontard 我认为我遇到的问题与您在github.com/mockito/mockito/issues/168 中打开的问题相同,无法存根从包可见类继承的公共方法
猜你喜欢
  • 2015-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多