[英]Mocking a class object using Mockito and PowerMockito
是否可以使用Mockito和/或PowerMockito模拟类对象?
就像是:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
首先,如评论中所述,您需要执行以下操作:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
但这由于PowerMock的限制而无法以通常的方式起作用。 您不能简单地从java.lang,java.net,java.io或其他系统类中模拟类,因为它们是由Java的引导类加载器加载的,并且不能由PowerMock的类加载器进行字节码操作。 (请参阅PowerMock常见问题解答 #4。)从PowerMock 1.2.5开始,您可以解决此问题。 如果您要测试的课程是这样的:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
然后,您将执行以下操作:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
@Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
如果无法重构代码,为什么不使用代理,因为选项不多,如@jherics所述,java系统类由引导类加载器加载,而powermock无法重新定义其字节码。
但是,Powermock现在附带了一个代理,它将允许模拟系统类。 在此处查看完整说明。
主要思想是修改您的java命令并添加:
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
该代理所做的基本操作是对类进行最终化处理,以允许将来在特定测试中进行模拟,这就是为什么您需要使用特定类型与代理进行通信的原因,例如与JUnit进行通信:
@Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
还支持TestNG。 只需查看Wiki页面以了解更多信息。
希望能有所帮助。
模拟类的替代方法可能是使用Factory。 我知道您担心重构,但这可以在不更改类的公共API的情况下完成。 您没有提供太多代码来理解要尝试测试的类,但是这里有一个无需更改API即可重构的示例。 这是一个琐碎的课程,但可能会给您一个想法。
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
当然,测试这个琐碎的类最简单的方法是使用真正的Runnable类,但是如果您尝试模拟该类,则会遇到问题。 因此,您可以这样重构它:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
现在,Instantiator使用相同的公共API完全完成了它以前所做的(非常简单)的事情,而该类的任何客户端都不需要自己进行任何特殊的注入。 但是,如果您想模拟工厂类并注入它,那很容易做到。
这个怎么样。 在类PCService中创建具有对象(MS)的get方法,然后对其进行模拟。
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
@Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.