JMockit Mock 私有方法和私有属性

前面说过 JMockit 因身处前线,所以简直无不可,本节例子演示 JMockit 怎么 Mock 私有方法和私有属性,示例虽然是静态方法和属性,但因采用的是反射手法,所以这种 Deencapsulation 的 Mock 手段同样适用于公有的方法或属性,无论是否静态。

本文所用 JMockit 版本为 1.6, 可能网上所搜索的方法与此有所不同,请注意 JMockit 版本差异。仍需重复一下,运行 JMockit 的例子 classpath 上必须让 jmockit.jar 在 junit.jar 之前,或用 javaagent 参数来加载 jmockit.jar,并且 junit 要 4.8 及以上版本.

1. Mock 私有方法(非静态类似)

fetchDataFromDB 是私有静态方法,正常测试的话肯定不过

这行

Deencapsulation.invoke(MyService.class, "fetchDataFromDB", "Unmi");

使用了反射的方式拦截了 MyService 的 fetchDataFromDB 方法,并非强设了它的返回值为  “http://unmi.cc”。关键是调用了 Deencapsulation.invoke() 方法,来看到这个类里还有哪些方法:

jmockit-deencapsulation

看到上图,我们必须要产生一些想法的,特别是 invoke 和 setField,以及它们的第一个参数可以是 Class,也可以是 Object,不难获知的是我们能够借助于它来 Mocket 私有方法和属性,不论它们是静态还是非静态的。

上面的测试用例可以见绿,输出为:

call MyService.fetchData

如果把测试代码中的调用处改为

String actual = MyService.fetchData("Unmis");

就要见红了,失败:

java.lang.RuntimeException: Not implemented yet!
at cc.unmi.MyService.fetchDataFromDB(MyService.java:10)
at cc.unmi.MyService.fetchData(MyService.java:6)
at cc.unmi.MyServiceTest.testFetchData(MyServiceTest.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:606)
................

对了,就是反射。受上面的点拨,怎么 Mock 属性已了然于心了,再行累述纯为拉长篇幅,不妨

2. Mock 私有属性(静态亦类似)

欲 Mock 的是 url 属性,从 fetchData 方法的 return url 可以检测到 Mock 后的值

断言成功,也用不着设置 result 值了, 而且这时候也用不着 new Expectations()  了。

Deencapsulation 是后来引入的,在 JMockit 0.999.19 中可以在  Expectations 中直接调用 invoke, setField 方法来改变运行中的值,Expectations 继承自 Invocations,原来的 Invocations 中定义了 invoke, setField, getFiled 等方法,新版的 JMockit 从  Invocations 中移除了那些方法。

记得当初我们用 @MockClass, @Mock, 再 Mockit.setUpMock() 三步曲来进行 Mock 操作,如今看来光 new Expectations() 这一招便可走遍天下。

类别: Java/JEE. 标签: , , . 阅读(6,191). 订阅评论. TrackBack.

Leave a Reply

Be the First to Comment!

avatar
wpDiscuz