- 軟件再工程:優(yōu)化現(xiàn)有軟件系統(tǒng)的方法與最佳實(shí)踐
- (美)Bradley Irby
- 1679字
- 2020-11-04 16:45:01
3.3 編寫測(cè)試
我們先看一下需要進(jìn)行測(cè)試的參考類和為其創(chuàng)建的單元測(cè)試。代碼清單3.4中的方法是先前計(jì)算貸款月付款方法示例的后續(xù)部分。
代碼清單3.4 測(cè)試中的方法
using System; namespace CodeSamples.Ch03_UnitTesting.Listing4 { public class FinancialFunctions { /// <summary> /// P = (Pv*R) / [1 - (1 + R)^(-n)] /// where /// Pv = Present Value (beginning /// value or amount of loan) /// APR = Annual Percentage Rate /// (one year time period) /// R = Periodic Interest Rate = /// APR/ # of interest periods per year /// P = Monthly Payment /// n = # of interest periods for overall /// time period (i.e., interest /// periods per year * number of years) /// </summary> /// <param name="pLoanAmount">Original amount of the loan</param> /// <param name="pYearlyInterestRate">Yearly interest rate</param> /// <param name="pNumMonthlyPayments">Num of mthly payments</param> public double CalcLoanPayment(double pLoanAmount, double pYearlyInterestRate, int pNumMonthlyPayments) { var mthlyInterestRate = pYearlyInterestRate / 12; var numerator = pLoanAmount * mthlyInterestRate; var denominator = (1 - Math.Pow(1 + mthlyInterestRate, -pNumMonthlyPayments)); var mthlyPayment = Math.Round(numerator / denominator, 2); return mthlyPayment; } } }
我們想要?jiǎng)?chuàng)建一些測(cè)試,以確保該方法對(duì)它支持的所有用例都有效。首先,編寫一個(gè)沒有錯(cuò)誤的測(cè)試方案。為了檢查結(jié)果的正確性,我們可以使用任意一種Web或是Excel中的按揭利率計(jì)算器。使用這種工具,我們計(jì)算出1000美元的貸款,在利率10%且30年內(nèi)還清的情況下,每月需支付8.78美元。在代碼清單3.5,我們編寫測(cè)試以傳入這些值,然后使用Assert確認(rèn)返回值是有效的。
代碼清單3.5 單元測(cè)試示例
using CodeSamples.Ch03_UnitTesting.Listing4; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CodeSamples.Ch03_UnitTesting.Listing5 { [TestClass] public class FinancialFunctionsUnitTest { [TestMethod] public void CalcLoanPayment_Loan1000Int10Pmt360_ReturnsProperPayment() { //Arrange var ex = new FinancialFunctions(); //Act var pmt = ex.CalcLoanPayment(1000, 10, 360); //Assert Assert.AreEqual(8.78, pmt); } } }
我們來一行一行地來看這個(gè)測(cè)試。首先要注意的是類中的TestClass屬性。我們必須告訴單元測(cè)試框架,該類是一個(gè)測(cè)試類。每個(gè)單元測(cè)試框架會(huì)有不同的屬性,但是它們都會(huì)有一些相通的屬性用以修飾測(cè)試類。對(duì)于一個(gè)測(cè)試方法而言,總會(huì)存在一個(gè)屬性,將一個(gè)方法表示成“測(cè)試方法”,我們稱這個(gè)屬性為TestMethod。
從技術(shù)的角度來說,類本身的名稱并不重要。所以通常我們用測(cè)試類的名稱來命名它,并在末尾加上UnitTest字樣。這里的方法名在技術(shù)層面上來說也不太重要,因?yàn)樗粫?huì)被任何代碼調(diào)用。在我們使用的命名標(biāo)準(zhǔn)中,一個(gè)單元測(cè)試以被測(cè)試的方法或?qū)傩缘拿Q開頭,中間加上被測(cè)試的特定用例的條件信息,最后加上預(yù)期的結(jié)果信息。假設(shè)我們測(cè)試的是CalcLoanPayment方法,該方法將會(huì)在貸款金額為1000美元,年利率為10%,貸款時(shí)間為360個(gè)月的情況下被調(diào)用,并且會(huì)返回正確的應(yīng)付款。根據(jù)這個(gè)情況,我們會(huì)得到如下的名稱:CalcLoanPayment_Loan1000Int10Pmt360_ReturnsProperPayment。名稱應(yīng)該描述得足夠清楚,那樣的話,當(dāng)你在測(cè)試過程中看到它旁邊有一個(gè)紅色的"fail"指示信息時(shí),就會(huì)知道當(dāng)前這個(gè)測(cè)試失敗了。
測(cè)試方法的主體非常簡(jiǎn)單。創(chuàng)建我們希望測(cè)試的類的新實(shí)例,然后在測(cè)試時(shí)使用合適的參數(shù)來調(diào)用該方法。這個(gè)方法中我們之前唯一沒見過的代碼是Assert行。關(guān)鍵字Assert確保我們測(cè)試的方法正常工作。通過使用Assert語句來測(cè)試該方法的結(jié)果,我們可以確保在給定值下,CalcLoanPayment方法能夠正常工作。如果返回的是我們預(yù)期的值,則這個(gè)測(cè)試通過;否則,測(cè)試失敗。
這種類型的測(cè)試結(jié)構(gòu)稱為Arrange-Act-Assert。測(cè)試的第一步是對(duì)類進(jìn)行排列,以便它們能夠反映我們想要測(cè)試的情況。然后操作被測(cè)試的類執(zhí)行我們想要測(cè)試的代碼。最后使用斷言確定返回值(或是采取的操作)對(duì)于我們的測(cè)試是正確的。如圖3.5所示,當(dāng)我們運(yùn)行這個(gè)測(cè)試時(shí),可以看到我們的方法返回了一個(gè)錯(cuò)誤的值。我們找到了第一個(gè)缺陷!圖3.5里那部分錯(cuò)誤消息顯示了預(yù)期值和實(shí)際返回值。
圖3.5 第一次測(cè)試失敗
檢查代碼,我們可以發(fā)現(xiàn)輸入的利率是一個(gè)0~100之間的數(shù),然而代碼期望一個(gè)0~1之間的數(shù)。我們可以改測(cè)試也可以改代碼,這取決于我們認(rèn)為哪個(gè)是錯(cuò)的。由于說明年利率一般用10%而不是0.1,因此我們?cè)试S用戶輸入1~100之間的數(shù),所以年利率10是有效的。這意味著我們必須更新業(yè)務(wù)邏輯以適應(yīng)這種輸入,如代碼清單3.6所示。
代碼清單3.6 測(cè)試下修復(fù)的單元
using System; namespace CodeSamples.Ch03_UnitTesting.Listing6 { public class FinancialFunctions { /// <summary> /// P = (Pv*R) / [1 - (1 + R)^(-n)] /// where /// Pv = Present Value (beginning /// value or amount of loan) /// APR = Annual Percentage Rate /// (one year time period) /// R = Periodic Interest Rate = /// APR/ # of interest periods per year /// P = Monthly Payment /// n = # of interest periods for overall /// time period (i.e., interest /// periods per year * number of years) /// </summary> /// <param name="pLoanAmount">Original amount of the loan</param> /// <param name="pYearlyInterestRate">Yearly interest rate</param> /// <param name="pNumMonthlyPayments">Num of mthly payments</param> public double CalcLoanPayment(double pLoanAmount, double pYearlyInterestRate, int pNumMonthlyPayments) { //Change the divisor for the yearly interest rate var mthlyInterestRate = pYearlyInterestRate / 1200; var numerator = pLoanAmount * mthlyInterestRate; var denominator = (1 - Math.Pow(1 + mthlyInterestRate, -pNumMonthlyPayments)); var mthlyPayment = Math.Round(numerator / denominator, 2); return mthlyPayment; } } }
再次運(yùn)行該測(cè)試以證明現(xiàn)在的代碼能正常運(yùn)行,如圖3.6所示。
圖3.6 測(cè)試下修復(fù)的系統(tǒng)
如代碼清單3.7所示,現(xiàn)在我們可以增加更多的方法來測(cè)試不同的方案并確保返回值是有效的。
代碼清單3.7 附加的單元測(cè)試
using CodeSamples.Ch03_UnitTesting.Listing4; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace CodeSamples.Ch03_UnitTesting.Listing7 { [TestClass] public class FinancialFunctionsUnitTest { [TestMethod] public void CalcLoanPayment_Loan1000Int10Pmt360_ReturnsPmt() { //Arrange var ex = new FinancialFunctions(); //Act var pmt = ex.CalcLoanPayment(1000, 10, 360); //Assert Assert.AreEqual(8.78, pmt); } [TestMethod] public void CalcLoanPayment_Loan1000Int5Pmt360_ReturnsPmt() { //Arrange var ex = new FinancialFunctions(); //Act var pmt = ex.CalcLoanPayment(1000, 15, 360); //Assert Assert.AreEqual(12.64, pmt); } [TestMethod] public void CalcLoanPayment_Loan1000Int10Pmt12_ReturnsPmt() { //Arrange var ex = new FinancialFunctions(); //Act var pmt = ex.CalcLoanPayment(1000, 10, 12); //Assert Assert.AreEqual(87.92, pmt); } } }
所以這些測(cè)試都應(yīng)該通過,如圖3.7所示。
圖3.7 成功運(yùn)行單元測(cè)試
- 極簡(jiǎn)算法史:從數(shù)學(xué)到機(jī)器的故事
- Flutter開發(fā)實(shí)戰(zhàn)詳解
- The Modern C++ Challenge
- Debian 7:System Administration Best Practices
- Spring Boot+Spring Cloud+Vue+Element項(xiàng)目實(shí)戰(zhàn):手把手教你開發(fā)權(quán)限管理系統(tǒng)
- Learning Bayesian Models with R
- 精通軟件性能測(cè)試與LoadRunner實(shí)戰(zhàn)(第2版)
- 重學(xué)Java設(shè)計(jì)模式
- Python機(jī)器學(xué)習(xí)經(jīng)典實(shí)例
- Mastering Rust
- PhoneGap:Beginner's Guide(Third Edition)
- Integrating Facebook iOS SDK with Your Application
- INSTANT Yii 1.1 Application Development Starter
- Python商務(wù)數(shù)據(jù)分析(微課版)
- Application Development with Parse using iOS SDK