如何用私有字段模拟 class?

How do I mock a class with private fields?

我正在尝试使用 Mockito 测试单例 class,如下所示:

  public class Single {
     private ID id;
     private Single(){}  //private constructor 
     public static Single getSingle(){ // ***code to get instance*** }

     // method I want to test
     public String getName(){ 
        String name = id.getRawName(); // need field id here
        ** additional operations on name ** // code need to be tested
        return name;
     }

  }

我试图模拟这个 class 并使用反射设置字段 "id",如下所示:

Single sg = Mockito.mock(Sincle.class);
Field myID = sg.getClass().getDeclaredField("id"); // fails here
myID.setAccessible(true);
myID.set(sg, <ID instance>);

但是它在 getDeclaredField() 方法中失败了,除了

java.lang.NoSuchFieldException: id

我猜这是因为 id 字段在实例 sg 中是 null

所以我想知道是否可以在不修改原始方法的情况下测试此方法class?

模拟不是真实对象。您不能设置模拟的声明字段,因为它不存在1!

当您编写测试时,您通常希望模拟所有 不是 :

的 classes

因此,您真正想要嘲笑的是 ExternalCall,您并没有真正解释它在您的问题中是如何工作的。但是,如果是静态方法,则需要使用PowerMock. See: Mocking static methods with Mockito

请注意,您的错误是 NoSuchFieldException,因为您实际上没有真实的实例。 不是 因为:

I guess it's because id field is null in instance sg.

因为实际上不存在1 在mockito生成的subclass ,不是因为 null.

1:它确实存在于 mock 的 superclass(在本例中,Single),但它的值被 mocking 行为捕获并被忽略,除非你使用它作为一个部分模拟。然而,这是一个技术细节,与正确使用 Mockito 无关。

...anything I can do to test this method without modify the original class?

是的,有。将 Mockito 用于日常用途:

when(sg.getId()).thenReturn("123")