Java 如何用私有字段模拟类?
我试图用Mockito测试一个单例类,类似这样: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(){
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
,但是一旦你使用了一个真正的单个对象,你就可以用反射设置这个字段。但最好是在你真正的应用程序中使用它的工作方式。