原創(chuàng)|使用教程|編輯:鄭恭琳|2020-12-07 11:29:15.390|閱讀 337 次
概述:參數(shù)化測試是定義和運(yùn)行多個(gè)測試用例的好方法,它們之間的唯一區(qū)別是數(shù)據(jù)。在這里,我們看一下JUnit測試常用的三個(gè)不同框架。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
參數(shù)化測試是定義和運(yùn)行多個(gè)測試用例的好方法,它們之間的唯一區(qū)別是數(shù)據(jù)。在這里,我們看一下JUnit測試常用的三個(gè)不同框架。
在編寫單元測試時(shí),通常會(huì)在測試方法本身中初始化方法輸入?yún)?shù)和預(yù)期結(jié)果。在某些情況下,使用少量輸入就足夠了;但是,在某些情況下,我們需要使用大量的值來驗(yàn)證代碼中的所有功能。參數(shù)化測試是定義和運(yùn)行多個(gè)測試用例的好方法,它們之間的唯一區(qū)別是數(shù)據(jù)。他們可以驗(yàn)證各種值的代碼行為,包括邊界情況。參數(shù)化測試可以增加代碼覆蓋率,并確保代碼按預(yù)期運(yùn)行。
有許多用于Java的良好參數(shù)化框架。在本文中,我們將研究JUnit測試常用的三個(gè)不同框架,并將它們與每個(gè)測試的結(jié)構(gòu)示例進(jìn)行比較。最后,我們將探索如何簡化和加速參數(shù)化測試的創(chuàng)建。
讓我們比較一下三種最常見的框架:JUnit 4,JunitParams和JUnit5。每個(gè)JUnit參數(shù)化框架都有自己的優(yōu)點(diǎn)和缺點(diǎn)。
JUnit 4
優(yōu)點(diǎn):
缺點(diǎn):
JunitParams
優(yōu)點(diǎn):
缺點(diǎn):
JUnit 5
優(yōu)點(diǎn):
缺點(diǎn):
例如,假設(shè)我們有一種處理銀行貸款請求的方法。我們可能會(huì)編寫一個(gè)單元測試,以指定貸款請求金額、預(yù)付定金金額和其他值。然后,我們將創(chuàng)建斷言來驗(yàn)證響應(yīng)——貸款可以被批準(zhǔn)或拒絕,并且響應(yīng)可以指定貸款的條款。
例如:
public LoanResponse requestLoan(float loanAmount, float downPayment, float availableFunds) { LoanResponse response = new LoanResponse(); response.setApproved(true); if (availableFunds < downPayment) { response.setApproved(false); response.setMessage(“error.insufficient.funds.for.down.payment“); return response; } if (downPayment / loanAmount < 0.1) { response.setApproved(false); response.setMessage(“error.insufficient.down.payment“); } return response; }
首先,讓我們看一下上述方法的常規(guī)測試:
@Test public void testRequestLoan() throws Throwable { // Given LoanProcessor underTest = new LoanProcessor(); // When LoanResponse result = underTest.requestLoan(1000f, 200f, 250f); // Then assertNotNull(result); assertTrue(result.isApproved()); assertNull(result.getMessage()); }
在此示例中,我們通過請求1000美元的貸款,200美元的首付并指示請求者有250美元的可用資金來測試我們的方法。然后,測試將驗(yàn)證貸款是否已獲批準(zhǔn),并且未在響應(yīng)中提供任何信息。
為了確保對我們的requestLoan()方法進(jìn)行了徹底的測試,我們需要使用各種預(yù)付款,請求的貸款金額和可用資金進(jìn)行測試。例如,讓我們測試一筆零首付的100萬美元貸款請求,該請求應(yīng)被拒絕。我們可以簡單地用不同的值復(fù)制現(xiàn)有測試,但是由于測試邏輯相同,因此參數(shù)化測試效率更高。
我們將參數(shù)化請求的貸款金額,預(yù)付款和可用資金以及預(yù)期的結(jié)果:貸款是否被批準(zhǔn),以及在驗(yàn)證后返回的消息。每組請求數(shù)據(jù)及其預(yù)期結(jié)果將成為其自己的測試用例。
讓我們從一個(gè)Junit 4 Parameterized示例開始。要?jiǎng)?chuàng)建參數(shù)化測試,我們首先需要定義測試的變量。我們還需要包括一個(gè)構(gòu)造函數(shù)來初始化它們:
@RunWith(Parameterized.class) public class LoanProcessorParameterizedTest { float loanAmount; float downPayment; float availableFunds; boolean expectApproved; String expectedMessage; public LoanProcessorParameterizedTest(float loanAmount, float downPayment, float availableFunds, boolean expectApproved, String expectedMessage) { this.loanAmount = loanAmount; this.downPayment = downPayment; this.availableFunds = availableFunds; this.expectApproved = expectApproved; this.expectedMessage = expectedMessage; } // … }
在這里,我們看到該測試使用@RunWith批注指定該測試將與Junit4參數(shù)化運(yùn)行器一起運(yùn)行。 該跑步者知道正在尋找一種方法,該方法將為測試提供值集(用@Parameters注釋),正確初始化測試并運(yùn)行多行測試。
請注意,每個(gè)參數(shù)都在測試類中定義為一個(gè)字段,并且構(gòu)造函數(shù)初始化這些值(如果您不想創(chuàng)建構(gòu)造函數(shù),也可以使用@Parameter注釋將值注入字段)。對于值集中的每一行,參數(shù)化運(yùn)行器將實(shí)例化測試類并運(yùn)行該類中的每個(gè)測試。
讓我們添加一個(gè)為參數(shù)化運(yùn)行器提供參數(shù)的方法:
@Parameters(name = “Run {index}: loanAmount={0}, downPayment={1}, availableFunds={2}, expectApproved={3}, expectedMessage={4}“) public static Iterable<Object[]> data() throws Throwable { return Arrays.asList(new Object[][] { { 1000.0f, 200.0f, 250.0f, true, null } }); }
值集通過data()方法構(gòu)建為“對象數(shù)組列表”,并使用@Parameters進(jìn)行注釋。請注意,@ Parameters使用占位符設(shè)置測試的名稱,將在運(yùn)行測試時(shí)將其替換。稍后我們將看到,這使得查看測試結(jié)果中的值更加容易。當(dāng)前,只有一行數(shù)據(jù)用于測試應(yīng)批準(zhǔn)貸款的情況。我們可以添加更多行以增加被測方法的覆蓋范圍。
@Parameters(name = “Run {index}: loanAmount={0}, downPayment={1}, availableFunds={2}, expectApproved={3}, expectedMessage={4}“) public static Iterable<Object[]> data() throws Throwable { return Arrays.asList(new Object[][] { { 1000.0f, 200.0f, 250.0f, true, null }, { 1000.0f, 50.0f, 250.0f, false, “error.insufficient.down.payment“ }, { 1000.0f, 200.0f, 150.0f, false, “error.insufficient.funds.for.down.payment“ } }); }
在這里,我們有一個(gè)測試案例,其中貸款將被批準(zhǔn),而另外兩個(gè)案例中,由于不同的原因而不應(yīng)被批準(zhǔn)。我們可能要添加使用零或負(fù)值的行以及測試邊界條件。
現(xiàn)在我們準(zhǔn)備創(chuàng)建測試方法:
@Test public void testRequestLoan() throws Throwable { // Given LoanProcessor underTest = new LoanProcessor(); // When LoanResponse result = underTest.requestLoan(loanAmount, downPayment, availableFunds); // Then assertNotNull(result); assertEquals(expectApproved, result.isApproved()); assertEquals(expectedMessage, result.getMessage()); }
在這里,我們在調(diào)用requestLoan()方法并驗(yàn)證結(jié)果時(shí)引用這些字段。
JunitParams庫通過允許將參數(shù)直接傳遞給測試方法來簡化參數(shù)化測試語法。參數(shù)值由單獨(dú)的方法提供,其名稱在@Parameters批注中引用。
@RunWith(JUnitParamsRunner.class) public class LoanProcessorParameterizedTest2 { @Test @Parameters(method = “testRequestLoan_Parameters“) public void testRequestLoan(float loanAmount, float downPayment, float availableFunds, boolean expectApproved, String expectedMessage) throws Throwable { … } @SuppressWarnings(“unused“) private static Object[][] testRequestLoan_Parameters() throws Throwable { // Parameters: loanAmount={0}, downPayment={1}, availableFunds={2}, expectApproved={3}, expectedMessage={4} return new Object[][] { { 1000.0f, 200.0f, 250.0f, true, null }, { 1000.0f, 50.0f, 250.0f, false, “error.insufficient.down.payment“}, { 1000.0f, 200.0f, 150.0f, false, “error.insufficient.funds.for.down.payment“ } }; } }
JunitParams的另一個(gè)好處是,除了在代碼中提供值外,它還支持使用CSV文件提供值。這允許將測試與數(shù)據(jù)分離,并在不更新代碼的情況下更新數(shù)據(jù)值。
JUnit 5解決了JUnit 4的一些局限和缺點(diǎn)。與JunitParams一樣,Junit 5也簡化了參數(shù)化測試的語法。語法上最重要的變化是:
在Junit 5中定義相同的示例如下所示:
public class LoanProcessorParameterizedTest { @ParameterizedTest(name=“Run {index}: loanAmount={0}, downPayment={1}, availableFunds={2}, expectApproved={3}, expectedMessage={4}“) @MethodSource(“testRequestLoan_Parameters“) public void testRequestLoan(float loanAmount, float downPayment, float availableFunds, boolean expectApproved, String expectedMessage) throws Throwable { … } static Stream<Arguments> testRequestLoan_Parameters() throws Throwable { return Stream.of( Arguments.of(1000.0f, 200.0f, 250.0f, true, null), Arguments.of(1000.0f, 50.0f, 250.0f, false, “error.insufficient.down.payment“), Arguments.of(1000.0f, 200.0f, 150.0f, false, “error.insufficient.funds.for.down.payment“) ); } }
可以想象,編寫上面的參數(shù)化測試可能會(huì)有些麻煩。對于每個(gè)參數(shù)化的測試框架,都需要正確編寫一些樣板代碼。記住正確的結(jié)構(gòu)可能很困難,而且要花時(shí)間寫出來。為了使此操作更容易,您可以使用Parasoft Jtest自動(dòng)生成參數(shù)化測試,就像上面描述的那樣。為此,只需選擇要為其生成測試的方法(在Eclipse或IntelliJ中),即可:
使用默認(rèn)值和斷言生成測試。然后,您可以使用實(shí)際輸入值和斷言配置測試,并將更多數(shù)據(jù)行添加到data()方法。
Parasoft Jtest可以直接在Eclipse和IntelliJ中運(yùn)行參數(shù)化測試。
Eclipse中的JUnit視圖
請注意,如圖所示,每個(gè)測試的名稱都包含來自數(shù)據(jù)集的輸入值和預(yù)期結(jié)果值。由于在每種情況下都會(huì)顯示輸入?yún)?shù)和預(yù)期的輸出,因此可以使測試失敗時(shí)的調(diào)試更加容易。
您還可以使用Parasoft Jtest的“全部運(yùn)行”操作:
Parasoft Jtest中的“流樹”視圖
它分析測試流程并提供有關(guān)先前測試運(yùn)行的詳細(xì)信息。 這使您可以查看測試中發(fā)生的情況,而無需使用斷點(diǎn)或調(diào)試語句重新運(yùn)行測試。例如,您可以在“變量”視圖中看到參數(shù)化的值:
Parasoft Jtest中的變量視圖
我們審查的三個(gè)框架中的每一個(gè)都是不錯(cuò)的選擇,并且運(yùn)作良好。如果使用JUnit 4,則由于測試類的設(shè)計(jì)更加簡潔,并且能夠在同一類中定義多個(gè)測試方法,因此我傾向于使用JunitParams而不是內(nèi)置的JUnit 4 Parameterized框架。但是,如果使用JUnit 5,我建議您使用內(nèi)置的JUnit 5框架,因?yàn)樗梢越鉀QJUnit 4中的缺點(diǎn),并且不需要額外的庫。我還喜歡使用Parasoft Jtest的單元測試功能來提高參數(shù)化測試的創(chuàng)建、執(zhí)行和調(diào)試的效率。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn