使用@Mock注解的对象是否应该设置详细值?

Should Object using @Mock annotation be set detailed value?

我是 Mockito 的新手,我有一个问题。假设我尝试在我的测试方法中有一个对象实例。我知道我可以使用 @Mock 来拥有它,那是因为我们试图将测试与该对象方法隔离开来。但是,为了控制测试分支,我确实需要在此对象中设置一些值。我应该仍然使用 Mock 还是应该简单地使用新的 Object() 方式来实例化它?还是无所谓(每种方式都可以)?

谢谢。

让我们找出答案,好吗?!

import org.mockito.Mockito;

class Scratch {  
    public final static String STATIC_CONST = "static const";
    private final String JUST_CONST = "private const";
    protected String protectedField = "protected field";
    String packageProtectedField = null;

    public static void main(String[] args) {
        Scratch mocked = Mockito.mock(Scratch.class);
        System.out.println("static    = " + mocked.STATIC_CONST);
        System.out.println("const     = " + mocked.JUST_CONST);
        System.out.println("protected = " + mocked.protectedField);
        System.out.println("package   = " + mocked.packageProtectedField);

        mocked.packageProtectedField = "but now";
        System.out.println("updated  = " + mocked.packageProtectedField);
    }
}

以上打印:

static = static const

const = private const

protected = null

package = null

updated = but now

一些想法:

显然,static const 确实是您所期望的(我使用 mocked.STATIC_CONST 来获取值,但是嘿,它是静态的,所以该值不是来自 mocked 但无论如何从头开始 class 定义)。

有点令人惊讶,至少对我来说,分配 模拟对象的字段实际上有效。但请注意:原始 class 中的赋值仅对 final 字段有效。换句话说:Mockito 做对了,但不是针对非最终字段。

更令人惊讶的是,可以将值存储到模拟中...

但老实说,这些都不重要。你看,在合理的设计中,所有可变字段首先应该是 private。该可变状态代表了对象的绝对核心。 外部代码应该处理这些!换句话说:理想情况下,即使您的测试也不关心对象的内部状态(在极少数情况下,使用 package protected getter 方法来访问内部状态以便于验证可能是有意义的,但是那应该是一个罕见的例外)。

除此之外:当你模拟一个对象时,你绝对不应该以任何方式处理那个模拟的字段。你看:那个模拟中的所有 方法 ......它们与你 class 中的原始源代码无关。它们只是:您可以 configure/verify 使用相应的 Mockito 方法的空壳。让它沉入:模拟对象中字段的实际内容无关紧要:因为通常处理这些字段的方法......“不存在”!

所以,长话短说:如图所示,模拟对象可以携带状态。但是正如所解释的那样:您应该完全忽略该方面。使用模拟的唯一正确方法是通过 specifying/verifying 方法调用它们。

最后:我希望 EasyMock、PowerMock(ito) 的行为方式相似。另一方面,当其他模拟框架的实际行为略有不同时,我也不会感到惊讶。我只使用 Mockito 进行了测试,因为恕我直言,在 2018 年,Mockito 是唯一一个在为 JVM 编写单元测试时应该使用的模拟框架。