java mock私有方法_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 私有方法(非靜態類似)
package cc.unmi;
public class MyService {
public static String fetchData(String name){
System.out.println("call MyService.fetchData");
return fetchDataFromDB(name);
}
private static String fetchDataFromDB(String name){
throw new RuntimeException("Not implemented yet!");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
packagecc.unmi;
publicclassMyService{
publicstaticStringfetchData(Stringname){
System.out.println("call MyService.fetchData");
returnfetchDataFromDB(name);
}
privatestaticStringfetchDataFromDB(Stringname){
thrownewRuntimeException("Not implemented yet!");
}
}
fetchDataFromDB 是私有靜態方法,正常測試的話肯定不過
package cc.unmi;
import mockit.Deencapsulation;
import mockit.Expectations;
import org.junit.Assert;
import org.junit.Test;
public class MyServiceTest {
@Test
public void testFetchData() {
new Expectations(MyService.class) {
{
Deencapsulation.invoke(MyService.class, "fetchDataFromDB", "Unmi");
result = "http://unmi.cc";
}
};
String actual = MyService.fetchData("Unmi");
Assert.assertEquals("http://unmi.cc", actual);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
packagecc.unmi;
importmockit.Deencapsulation;
importmockit.Expectations;
importorg.junit.Assert;
importorg.junit.Test;
publicclassMyServiceTest{
@Test
publicvoidtestFetchData(){
newExpectations(MyService.class){
{
Deencapsulation.invoke(MyService.class,"fetchDataFromDB","Unmi");
result="http://unmi.cc";
}
};
Stringactual=MyService.fetchData("Unmi");
Assert.assertEquals("http://unmi.cc",actual);
}
}
這行
Deencapsulation.invoke(MyService.class, "fetchDataFromDB", "Unmi");
使用了反射的方式攔截了 MyService 的 fetchDataFromDB 方法,并非強設了它的返回值為? “http://unmi.cc”。關鍵是調用了 Deencapsulation.invoke() 方法,來看到這個類里還有哪些方法:
看到上圖,我們必須要產生一些想法的,特別是 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 私有屬性(靜態亦類似)
package cc.unmi;
public class MyService {
private String url = "";
public String fetchData(String name){
System.out.println("call MyService.fetchData");
return this.url;
}
}
1
2
3
4
5
6
7
8
9
10
11
packagecc.unmi;
publicclassMyService{
privateStringurl="";
publicStringfetchData(Stringname){
System.out.println("call MyService.fetchData");
returnthis.url;
}
}
欲 Mock 的是 url 屬性,從 fetchData 方法的 return url 可以檢測到 Mock 后的值
package cc.unmi;
import mockit.Deencapsulation;
import mockit.Expectations;
import org.junit.Assert;
import org.junit.Test;
public class MyServiceTest {
@Test
public void testFetchData() {
final MyService service = new MyService();
Deencapsulation.setField(service, "url", "http://unmi.cc");
String actual = service.fetchData("Unmi");
Assert.assertEquals("http://unmi.cc", actual);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
packagecc.unmi;
importmockit.Deencapsulation;
importmockit.Expectations;
importorg.junit.Assert;
importorg.junit.Test;
publicclassMyServiceTest{
@Test
publicvoidtestFetchData(){
finalMyServiceservice=newMyService();
Deencapsulation.setField(service,"url","http://unmi.cc");
Stringactual=service.fetchData("Unmi");
Assert.assertEquals("http://unmi.cc",actual);
}
}
斷言成功,也用不著設置 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 mock私有方法_JMockit Mock 私有方法和私有属性的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 规模化敏捷转型中,哪些问题会被经常问到?
- 下一篇: java如何做聚类分析_K-means算
