Java 如何用私有字段模拟类?

Java 如何用私有字段模拟类?,java,testing,reflection,mockito,Java,Testing,Reflection,Mockito,我试图用Mockito测试一个单例类,类似这样: 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(){

我试图用Mockito测试一个单例类,类似这样:

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

  }
Single sg = Mockito.mock(Sincle.class);
Field myID = sg.getClass().getDeclaredField("id"); // fails here
myID.setAccessible(true);
myID.set(sg, <ID instance>);
我试图模拟这个类,并用反射设置字段“id”,如下所示:

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

  }
Single sg = Mockito.mock(Sincle.class);
Field myID = sg.getClass().getDeclaredField("id"); // fails here
myID.setAccessible(true);
myID.set(sg, <ID instance>);
Single sg=Mockito.mock(Sincle.class);
字段myID=sg.getClass().getDeclaredField(“id”);//这里失败了
myID.setAccessible(true);
myID.set(sg,);
但是,它在
getDeclaredField()
方法中失败,例外情况除外

java.lang.NoSuchFieldException:id

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

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

模拟不是真正的对象。无法设置模拟的声明字段,因为它不存在1! 编写测试时,通常要模拟所有而不是的类:

  • 类(在本例中为
    单个
    )类
  • 数据结构(如
    列表
    )和其他
因此,您真正想要模仿的是
ExternalCall
,您没有在问题中真正解释它是如何工作的。但是,如果是静态方法,则需要使用。见:

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

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

这是因为字段实际上不存在于mockito生成的子类中,而不是因为它是
null

1:它确实存在于mock的超类中(在本例中为
Single
),但是它的值被mock行为捕获,并且被忽略,除非您将其用作部分mock。但是,这是一个技术细节,与正确使用Mockito无关

…我可以做什么来测试此方法而不修改 原班人马

是的,有。将Mockito用于面包和黄油用途:


when(sg.getId())。然后返回(“123”)

这个问题的答案似乎有助于解释其中一些行为。不完全确定我可能遗漏了什么,但为什么不在(sg.getId())时返回(“123”)?模拟的目的是模拟单元的外部API,这意味着内部应该通常是无关的。如果我必须猜测反射本身失败的原因,那么
sg.getClass()
将返回Mockito创建的某个动态类,该类扩展了
Single
。使用
Single.class.getDeclaredField(“id”)
可能会起作用。但在我看来,你仍然会面临一个相当可怕的考验。@MarkPeters谢谢你的回答。我认为你的猜测比我的更有意义。我只是稍微修改了我的示例,以解释为什么我不能使用Mockito.when()。你能再解释一下为什么这是一个糟糕的测试吗?@hj690:从你的编辑来看,
ExternalCall
似乎是你应该模仿的。@MarkPeters我刚刚编辑了我的示例,解释了为什么我不能模仿ExternalCall。@hj690在你的实际应用程序中如何设置
ID
,但是一旦你使用了一个真正的
单个
对象,你就可以用反射设置这个字段。但最好是在你真正的应用程序中使用它的工作方式。