Java 用Mockito截获真正的非静态方法调用
是否有任何方法可以使用Java 用Mockito截获真正的非静态方法调用,java,mocking,mockito,powermockito,intercept,Java,Mocking,Mockito,Powermockito,Intercept,是否有任何方法可以使用Mockito或PowerMockito,拦截对对象的非静态方法的调用,或者至少是对单例对象的调用 以下类别提供了一个示例: public class Singleton { private static Singleton INSTANCE = null; private Singleton(Object parameter) {} public static Singleton getInstance(Object parameter) { i
Mockito
或PowerMockito
,拦截对对象的非静态方法的调用,或者至少是对单例对象的调用
以下类别提供了一个示例:
public class Singleton {
private static Singleton INSTANCE = null;
private Singleton(Object parameter) {}
public static Singleton getInstance(Object parameter) {
if (INSTANCE == null) {
INSTANCE = new Singleton(parameter);
}
return INSTANCE;
}
public String process(String a, String b) {
return (a + b);
}
// Other methods
}
public class Foreign {
private Foreign() {}
public static void main(String[] args) {
System.out.println(Singleton.getInstance(new Object()).process("alpha", "beta"));
}
}
Singleton
对象是在Foreign
类中创建的,不受某些测试代码(上面未显示)的控制。这两个类都不能修改。目标是拦截对测试代码中非静态process()
方法的调用,以便对于某些值,返回不同的结果,例如调用
Singleton.getInstance(new Object()).process("alpha", "beta");
mock返回“alpha-beta”
,而不是预期的“alpha-beta”
一种解决方案可能是拦截Singleton.getInstance()
方法来实例化Singleton的自定义子类,例如使用
public class SubSingleton extends Singleton {
public SubSingleton(Object parameter) {
super(parameter);
}
public String process(String a, String b) {
if ("alpha".equals(a) && "beta".equals(b)) {
return a + "-" + b;
}
return super.process(a + b);
}
}
然后,对Singleton.process()
方法的调用将被拦截,如下所示:
Object parameter = new Object();
PowerMockito.doReturn(new SubSingleton(parameter)).when(Singleton.class, "getInstance", parameter);
但是,上面的Singleton
类只提供了一个私有构造函数,因此不能对其进行扩展。使用PowerMockito.whenNew()
返回部分模拟(spy)也不起作用,因为Singleton
类不提供无参数构造函数
所需的模拟能否以任何其他方式实现?可以对非单例类执行此操作吗?首先,可以对具有某些参数的构造函数的对象使用whenNew:
@RunWith(PowerMockRunner.class)
@PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
@Mock
Singleton singletonMock;
@Before
public void setUp() throws Exception {
PowerMockito.whenNew(Singleton.class)
.withAnyArguments()
.thenReturn(singletonMock);
}
@Test
public void testMockNew() throws Exception {
Mockito.when(singletonMock.process(anyString(), anyString())).thenReturn("sasa");
Foreign.main(new String[0]);
}
}
其次,为什么不使用stub getInstance而不是new:
@RunWith(PowerMockRunner.class)
@PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
@Test
public void testMockNew() {
PowerMockito.mockStatic(Singleton.class);
Singleton singletonMock = Mockito.mock(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process(anyString(), anyString())).thenReturn("sasa");
Foreign.main(new String[0]);
}
}
第三,拦截处理方法:
- 创造真正的单身
- 创建一个模拟单例
- 模拟静态getInstance以返回模拟。注意:在获得真实实例后,必须调用mockStatic
- 使用Answer检查
call上的参数process
- 如果符合所需模式,则返回所需答案
- else在实单例上调用实方法
@RunWith(PowerMockRunner.class)
@PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
@Test
public void testMockNew() {
var singletonReal = Singleton.getInstance(new Object());
var singletonMock = Mockito.spy(singletonReal);
PowerMockito.mockStatic(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process("alpha", "beta")).thenReturn("sasa");
// NOTE: real method is called for other args
Foreign.main(new String[0]);
}
}
第一个方法不提供解决方案,因为它拦截模拟对象的
process()
,而不是singleton,它实际上是由Foreign
和其他类调用singleton
类的其他方法使用的。这同样适用于第二种方法,因为Singleton
类也有其他方法(在问题中阐明)。第三种方法应该适用于单例,因为间谍活动发生在真实对象上。是否适用于非单身人士+谢谢你的回答。我的回答给出了解决方案的各个阶段。第一个例子表明,当构造函数有参数时,可以使用whenNew,您认为这是不可能的。2.如果还有其他方法,并且您只想截获一些调用,那么第三个和第四个代码段就是最好的选择(我的首选是第四个)。3.我对Singleton.getInstance(对象参数)
非常困惑,它接受一个参数,如果Singleton已经存在,就会忽略它。4.适用于非单身人士-我需要一个具体的例子。谢谢你的回答,+1并被接受。我评论的意思是,whenNew()
没有提供解决方案,因为它提供的是模拟对象,而不是真正的单例。2.根据我之前的评论,已于4日同意。3.代码是一个简化的示例,参数可以是任何东西,也可以有多个。4.外部类使用的任何应用程序,只要存在多个实例。如果传递模拟参数,则带有参数的私有构造函数并不总是可用的,因为对实际方法的调用可能不会产生有效的结果。
@RunWith(PowerMockRunner.class)
@PrepareForTest(Singleton.class)
public class SingletonPrivateNewTest {
@Test
public void testMockNew() {
var singletonReal = Singleton.getInstance(new Object());
var singletonMock = Mockito.spy(singletonReal);
PowerMockito.mockStatic(Singleton.class);
PowerMockito.when(Singleton.getInstance(any())).thenReturn(singletonMock);
Mockito.when(singletonMock.process("alpha", "beta")).thenReturn("sasa");
// NOTE: real method is called for other args
Foreign.main(new String[0]);
}
}