??在平常工作過程中,總會設(shè)計(jì)些工具類,里面通常使用靜態(tài)方法來實(shí)現(xiàn)。那么如何來對這些靜態(tài)方法進(jìn)行mock,以及如何驗(yàn)證靜態(tài)方法被調(diào)用?下面簡單介紹下如何使用Powermock來實(shí)現(xiàn)針對靜態(tài)方法的mock。
創(chuàng)新互聯(lián)專注于江干網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供江干營銷型網(wǎng)站建設(shè),江干網(wǎng)站制作、江干網(wǎng)頁設(shè)計(jì)、江干網(wǎng)站官網(wǎng)定制、小程序制作服務(wù),打造江干網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供江干網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
??首先我們設(shè)計(jì)一個(gè)靜態(tài)類如下(Utility.java):
??被測試類如下(UtilityHelper.java):
??在被測試類中分別定義了兩個(gè)方法,分別調(diào)用了Utility類里面的兩個(gè)靜態(tài)方法,下面我們通過對這兩個(gè)方法進(jìn)行測試,來介紹下使用Powermock對靜態(tài)方法進(jìn)行mock的各種用法。
??測試類如下(UtilityHelperTest.java):
可以看到雖然入?yún)⒎强?,但是由于返回值返回了true,使得調(diào)用sum方法返回的值是0。
??另外,如果我們想要驗(yàn)證某靜態(tài)方法是否被調(diào)用,或者被調(diào)用了幾次,我們可以用如下方式驗(yàn)證:
??先使用verifyStatic方法表明要驗(yàn)證靜態(tài)方法,可以帶參數(shù),也可以不帶參數(shù),其參數(shù)可以使用Mockito的times方法或never方法來表示其調(diào)用次數(shù)。下面緊跟著的一行則表示要驗(yàn)證的是哪個(gè)已經(jīng)mock的靜態(tài)方法。
??那么如果我們想對已經(jīng)mock的類的某個(gè)方法調(diào)用真實(shí)的方法,而不是調(diào)用mock方法,那么該如何處理呢?此處我們介紹兩種實(shí)現(xiàn):
??加了上面一行后,雖然也沒有對listIsNotNullOrEmpty進(jìn)行mock,但此時(shí)返回值是真正的值,說明沒有調(diào)用默認(rèn)的mock方法。使用spy后,雖然已經(jīng)對該類做了mockStatic處理,但此時(shí)該類中的所有方法仍然都會調(diào)用真實(shí)的方法,而不是默認(rèn)的mock方法。這種用法主要適用于只想要對某個(gè)類的少量方法進(jìn)行mock,其他方法仍然執(zhí)行真正的方法,平常寫時(shí),可以緊跟在mockStatic方法后。
??此行的含義就是調(diào)用到mock類的該方法執(zhí)行真正的方法,而不是mock方法。這種方式就是需要對每個(gè)要執(zhí)行的方法都要進(jìn)行相應(yīng)的mock處理。
??上述兩種方式,可以根據(jù)自己的需要進(jìn)行選擇使用哪一種。但是一定要記得,只要使用了mockStatic某類時(shí),該類中的所有方法就已經(jīng)都默認(rèn)被mock了, 在調(diào)用該類的方法時(shí),必須根據(jù)具體方法進(jìn)行相應(yīng)的處理。
??另外,重要的事說三遍: 如果要mock靜態(tài)方法,必須要在PrepareForTest后面加上該方法所在的類 。
package?cn.outofmemory.junit.jmockit;
import?mockit.NonStrictExpectations;
import?mockit.Injectable;
import?mockit.MockUp;
import?mockit.Mocked;
import?mockit.Mockit;
import?mockit.NonStrict;
import?mockit.Tested;
public?class?MockTargetTest?{
@BeforeClass
static?public?void?beforeClass()?{
Mockit.setUpMocks();
}
@Mocked
private?MockTarget?mt;
@Test
public?void?testPrivateMethodMock()?{???????
new?NonStrictExpectations(mt)?{
{
//?對私有方法進(jìn)行mock??
this.invoke(mt,?"privateMethod",?anyString);??
result?=?"Hello?Object";??
}
};
Object?actual?=?mt.publicMethod();
assertEquals(actual,"Hello?Object");
}
}
String content = null;
while(rs.next()) {
content = content + rs.getString("學(xué)生姓名") + "\t" + rs.getString("xxxx") + "\t" + rs.getString("xxx") + "\n";
}
textArea.setText(content);
按升序那個(gè),直接在sql里面控制就行了
SELECT ......... FROM .... ORDER BY 學(xué)號 ASC
單元測試是我們在軟件開發(fā)過程中經(jīng)常用到的一種軟件測試的方法,而今天我們就一起來了解一下,一個(gè)好的單元測試都是如何來編輯完成的。
1.使用框架來用于單元測試
Java提供了若干用于單元測試的框架。TestNG和JUnit是流行的測試框架。JUnit和TestNG的一些重要功能:
易于設(shè)置和運(yùn)行。
支持注釋。
允許忽略或分組并一起執(zhí)行某些測試。
支持參數(shù)化測試,即通過在運(yùn)行時(shí)指定不同的值來運(yùn)行單元測試。
通過與構(gòu)建工具,如Ant,Maven和Gradle集成來支持自動化的測試執(zhí)行。
EasyMock是一個(gè)模擬框架,是單元測試框架,如JUnit和TestNG的補(bǔ)充。EasyMock本身不是一個(gè)完整的框架。它只是添加了創(chuàng)建模擬對象以便于測試的能力。例如,我們想要測試的一個(gè)方法可以調(diào)用從數(shù)據(jù)庫獲取數(shù)據(jù)的DAO類。在這種情況下,EasyMock可用于創(chuàng)建返回硬編碼數(shù)據(jù)的MockDAO。這使我們能夠輕松地測試我們意向的方法,而不必?fù)?dān)心數(shù)據(jù)庫訪問。
2.謹(jǐn)慎使用測試驅(qū)動開發(fā)!
測試驅(qū)動開發(fā)(TDD)是一個(gè)軟件開發(fā)過程,在這過程中,在開始任何編碼之前,我們基于需求來編寫測試。由于還沒有編碼,測試初會失敗。然后寫入小量的代碼以通過測試。然后重構(gòu)代碼,直到被優(yōu)化。
目標(biāo)是編寫覆蓋所有需求的測試,而不是一開始就寫代碼,卻可能甚至都不能滿足需求。TDD是偉大的,因?yàn)樗鼘?dǎo)致簡單的模塊化代碼,且易于維護(hù)。總體開發(fā)速度加快,容易發(fā)現(xiàn)缺陷。此外,單元測試被創(chuàng)建作為TDD方法的副產(chǎn)品。
然而,TDD可能不適合所有的情況。在設(shè)計(jì)復(fù)雜的項(xiàng)目中,專注于簡單的設(shè)計(jì)以便于通過測試用例,而不提前思考可能會導(dǎo)致巨大的代碼更改。此外,TDD方法難以用于與遺留系統(tǒng),GUI應(yīng)用程序或與數(shù)據(jù)庫一起工作的應(yīng)用程序交互的系統(tǒng)。另外,測試需要隨著代碼的改變而更新。
因此,在決定采用TDD方法之前,應(yīng)考慮上述因素,并應(yīng)根據(jù)項(xiàng)目的性質(zhì)采取措施。
3.測量代碼覆蓋率
代碼覆蓋率衡量(以百分比表示)了在運(yùn)行單元測試時(shí)執(zhí)行的代碼量。通常,高覆蓋率的代碼包含未檢測到的錯(cuò)誤的幾率要低,因?yàn)槠涓嗟脑创a在測試過程中被執(zhí)行。云南電腦培訓(xùn)發(fā)現(xiàn)測量代碼覆蓋率的一些佳做法包括:
使用代碼覆蓋工具,如Clover,Corbetura,JaCoCo或Sonar。使用工具可以提高測試質(zhì)量,因?yàn)檫@些工具可以指出未經(jīng)測試的代碼區(qū)域,讓你能夠開發(fā)開發(fā)額外的測試來覆蓋這些領(lǐng)域。
JAVA
單例模式的幾種實(shí)現(xiàn)方法
餓漢式單例類
package
pattern.singleton;
//
餓漢式單例類
.
在類初始化時(shí),已經(jīng)自行實(shí)例化
public
class
Singleton1
{
//
私有的默認(rèn)構(gòu)造子
private
Singleton1()
{}
//
已經(jīng)自行實(shí)例化
private
static
final
Singleton1
single
=
new
Singleton1();
//
靜態(tài)工廠方法
public
static
Singleton1
getInstance()
{
return
single;
}
}
2.
懶漢式單例類
package
pattern.singleton;
//
懶漢式單例類
.
在第一次調(diào)用的時(shí)候?qū)嵗?/p>
public
class
Singleton2
{
//
私有的默認(rèn)構(gòu)造子
private
Singleton2()
{}
//
注意,這里沒有
final
private
static
Singleton2
single;
//
只實(shí)例化一次
static
{
single
=
new
Singleton2();
}
//
靜態(tài)工廠方法
public
synchronized
static
Singleton2
getInstance()
{
if
(single
==
null
)
{
single
=
new
Singleton2();
}
return
single;
}
}
在上面給出懶漢式單例類實(shí)現(xiàn)里對靜態(tài)工廠方法使用了同步化,以處理多線程環(huán)境。有些設(shè)計(jì)師在這里建議使用所謂的
"
雙重檢查成例
".
必須指出的是,
"
雙重檢查成例
"
不可以在
Java
語言中使用。不十分熟悉的讀者,可以看看后面給出的小節(jié)。
同
樣,由于構(gòu)造子是私有的,因此,此類不能被繼承。餓漢式單例類在自己被加載時(shí)就將自己實(shí)例化。即便加載器是靜態(tài)的,在餓漢
式單例類被加載時(shí)仍會將自己實(shí)例化。單從資源利用效率角度來講,這個(gè)比懶漢式單例類稍差些。從速度和反應(yīng)時(shí)間角度來講,
則
比懶漢式單例類稍好些。然而,懶漢式單例類在實(shí)例化時(shí),必須處
理好在多個(gè)線程同時(shí)首次引用此類時(shí)的訪問限制問題,特別是當(dāng)單例類作為資源控制器,在實(shí)例化時(shí)必然涉及資源初始化,而資源
初始化很有可能耗費(fèi)時(shí)間。這意味著出現(xiàn)多線程同時(shí)首次引用此類的機(jī)率變得較大。
餓漢式單例類可以在
Java
語言內(nèi)實(shí)現(xiàn),
但不易在
C++
內(nèi)實(shí)現(xiàn),因?yàn)殪o態(tài)初始化在
C++
里沒有固定的順序,因而靜態(tài)的
m_instance
變量的初始化與類的加載順序沒有保證,可能會出問題。這就是為什么
GoF
在提出單例類的概念時(shí),舉的例子是懶
漢式的。他們的書影響之大,以致
Java
語言中單例類的例子也大多是懶漢式的。實(shí)際上,本書認(rèn)為餓漢式單例類更符合
Java
語
言本身的特點(diǎn)。
3.
登記式單例類
.
package
pattern.singleton;
import
java.util.HashMap;
import
java.util.Map;
//
登記式單例類
.
//
類似
Spring
里面的方法,將類名注冊,下次從里面直接獲取。
public
class
Singleton3
{
private
static
MapString,Singleton3
map
=
new
HashMapString,Singleton3();
static
{
Singleton3
single
=
new
Singleton3();
map.put(single.getClass().getName(),
single);
}
//
保護(hù)的默認(rèn)構(gòu)造子
protected
Singleton3(){}
//
靜態(tài)工廠方法
,
返還此類惟一的實(shí)例
public
static
Singleton3
getInstance(String
name)
{
if
(name
==
null
)
{
name
=
Singleton3.
class
.getName();
System.out.println("name
==
null"+"---name="+name);
}
if
(map.get(name)
==
null
)
{
try
{
map.put(name,
(Singleton3)
Class.forName(name).newInstance());
}
catch
(InstantiationException
e)
{
e.printStackTrace();
}
catch
(IllegalAccessException
e)
{
e.printStackTrace();
}
catch
(ClassNotFoundException
e)
{
e.printStackTrace();
}
}
return
map.get(name);
}
//
一個(gè)示意性的商業(yè)方法
public
String
about()
{
return
"Hello,
I
am
RegSingleton.";
}
public
static
void
main(String[]
args)
{
Singleton3
single3
=
Singleton3.getInstance(
null
);
System.out.println(single3.about());
}
}