最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

【reading】【中文】 3.1 A New Way

2023-07-21 14:58 作者:武宣博  | 我要投稿

測(cè)試和選擇排序

中高級(jí)程序員最重要的技能之一是能夠判斷代碼是否正確。在本章中,我們將討論如何編寫(xiě)測(cè)試來(lái)評(píng)估代碼的正確性。同時(shí),我們還將介紹一種稱(chēng)為選擇排序的排序算法。

一種新的方法

當(dāng)你編寫(xiě)程序時(shí),它可能會(huì)有錯(cuò)誤。在課堂環(huán)境中,你通過(guò)用戶(hù)交互、代碼分析和自動(dòng)測(cè)試(在許多情況下最重要的)來(lái)增強(qiáng)代碼的正確性。當(dāng)然,自動(dòng)評(píng)分系統(tǒng)并不是魔法。它們是由教師編寫(xiě)的代碼,其本質(zhì)上與你自己編寫(xiě)的代碼并沒(méi)有太大區(qū)別。在真實(shí)世界中,這些測(cè)試是由程序員自己編寫(xiě)的,而不是由像喬·休格這樣的善良的第三方編寫(xiě)的。

在本章中,我們將探討如何編寫(xiě)我們自己的測(cè)試。我們的目標(biāo)是創(chuàng)建一個(gè)名為 Sort 的類(lèi),該類(lèi)提供了一個(gè) sort(String[] x) 方法,以對(duì)數(shù)組 x 中的字符串進(jìn)行排序。

作為一種全新的思考方式,我們將首先編寫(xiě) testSort(),僅在完成測(cè)試之后,才開(kāi)始編寫(xiě)實(shí)際的排序代碼。

特定目的的測(cè)試

為 Sort.sort 編寫(xiě)測(cè)試相對(duì)簡(jiǎn)單,盡管可能有些乏味。我們只需要?jiǎng)?chuàng)建一個(gè)輸入,調(diào)用 sort 方法,并檢查方法的輸出是否正確。如果輸出不正確,我們會(huì)輸出第一個(gè)不匹配項(xiàng)并終止測(cè)試。例如,我們可以創(chuàng)建一個(gè)如下所示的測(cè)試類(lèi):

我們可以通過(guò)創(chuàng)建一個(gè)空的 Sort.sort 方法來(lái)測(cè)試我們的測(cè)試,如下所示:

如果我們?cè)谶@個(gè)空的 Sort.sort 方法中運(yùn)行 testSort() 方法,我們將得到:

我們得到了一個(gè)錯(cuò)誤消息,這是一件好事!這意味著我們的測(cè)試有效。這非常有趣的一點(diǎn)是,我們現(xiàn)在為自己創(chuàng)造了一個(gè)小游戲,目標(biāo)是修改 Sort.sort 中的代碼,使得這個(gè)錯(cuò)誤消息不再出現(xiàn)。這有點(diǎn)像一個(gè)心理游戲,許多程序員發(fā)現(xiàn)為自己設(shè)計(jì)這些小迷題幾乎會(huì)上癮。

事實(shí)上,這非常類(lèi)似于為課程的自動(dòng)評(píng)分系統(tǒng)而努力,你發(fā)現(xiàn)自己迷戀于讓自動(dòng)評(píng)分系統(tǒng)給予你它的喜愛(ài)和贊賞?,F(xiàn)在,你有了為代碼創(chuàng)建一個(gè)評(píng)委的能力,只有通過(guò)正確完成代碼,才能贏得它們的崇敬。

重要說(shuō)明:你可能會(huì)問(wèn),為什么要遍歷整個(gè)數(shù)組?為什么不使用 == 檢查數(shù)組是否相等呢?原因是,當(dāng)我們測(cè)試兩個(gè)對(duì)象是否相等時(shí),不能簡(jiǎn)單地使用 == 運(yùn)算符。== 運(yùn)算符比較的是內(nèi)存中的字面位,例如 input == expected 檢查 input 和 expected 的地址是否相同,而不是數(shù)組中的值是否相同。因此,在 testSort 中,我們使用了一個(gè)循環(huán),并打印出第一個(gè)不匹配項(xiàng)。你也可以使用內(nèi)置的 java.util.Arrays.equals 方法來(lái)代替循環(huán)。

雖然上面的單個(gè)測(cè)試并不是太多工作,但是編寫(xiě)一套這樣的特定目的的測(cè)試將非常乏味,因?yàn)檫@將涉及到編寫(xiě)大量不同的循環(huán)和打印語(yǔ)句。在下一節(jié)中,我們將看到如何使用 org.junit 庫(kù)節(jié)省大量的工作。

JUnit 測(cè)試

org.junit 庫(kù)提供了許多有用的方法和實(shí)用的功能,可簡(jiǎn)化測(cè)試的編寫(xiě)。例如,我們可以使用以下方法替換上面簡(jiǎn)單的特定目的的測(cè)試:

這段代碼更簡(jiǎn)單,并且基本上完成了相同的工作,即如果數(shù)組不相等,則會(huì)告訴我們第一個(gè)不匹配項(xiàng)。例如,如果我們?cè)谝粋€(gè)什么都不做的 Sort.sort 方法上運(yùn)行 testSort(),我們將得到:

雖然這個(gè)輸出比我們特定目的的測(cè)試有點(diǎn)丑陋,但我們將在本章的最后看到如何使其更好看。

選擇排序

在編寫(xiě) Sort.sort 方法之前,我們需要一些排序算法的思路。也許最簡(jiǎn)單的排序算法是“選擇排序”。選擇排序由三個(gè)步驟組成:

  • 找到最小的項(xiàng)。

  • 將其移到最前面。

  • 對(duì)剩下的 N-1 個(gè)項(xiàng)進(jìn)行選擇排序(不會(huì)改動(dòng)前面的項(xiàng))。

例如,假設(shè)我們有數(shù)組 {6, 3, 7, 2, 8, 1}。該數(shù)組中最小的項(xiàng)是 1,因此我們將 1 移到開(kāi)頭。有兩種自然的方法可以實(shí)現(xiàn)這一點(diǎn):一種是將 1 放在開(kāi)頭并將所有數(shù)字往后移動(dòng),即 {1, 6, 3, 7, 2, 8}。然而,更高效的方法是將 1 與舊的第一個(gè)項(xiàng)(在本例中為 6)進(jìn)行交換,得到 {1, 3, 7, 2, 8, 6}。

我們只需要重復(fù)相同的過(guò)程,即可對(duì)剩下的數(shù)字進(jìn)行排序,即 {1, 3, 7, 2, 8, 6} 的最小項(xiàng)是 2。將其移到開(kāi)頭,我們得到 {1, 2, 7, 3, 8, 6}。繼續(xù)重復(fù)這個(gè)過(guò)程,直到我們得到一個(gè)排序好的數(shù)組,我們將得到 {1, 2, 3, 7, 8, 6},然后是 {1, 2, 3, 6, 8, 7},最后是 {1, 2, 3, 6, 7, 8}。

我們可以通過(guò)使用第 2.4 章介紹的不變量的概念,在任何數(shù)組上對(duì)這個(gè)排序算法的正確性進(jìn)行數(shù)學(xué)證明,但在本教程中我們不會(huì)這樣做。在繼續(xù)之前,試著自己寫(xiě)下一組短數(shù)字?jǐn)?shù)組,并對(duì)其執(zhí)行選擇排序,以確保你理解了思路。

現(xiàn)在我們知道選擇排序是如何工作的,我們可以在我們空白的 Sort.sort 方法中添加一些簡(jiǎn)短的注釋來(lái)指導(dǎo)我們的思考:

在接下來(lái)的幾節(jié)中,我將嘗試完成選擇排序的實(shí)現(xiàn)。我會(huì)像學(xué)生一樣逐步完成,并會(huì)有一些故意的錯(cuò)誤。這些故意的錯(cuò)誤是有益的,因?yàn)樗鼈儗椭菔緶y(cè)試的有用性。如果你在閱讀時(shí)注意到任何錯(cuò)誤,不要擔(dān)心,我們最終會(huì)對(duì)其進(jìn)行更正。

尋找最小項(xiàng)

最自然的開(kāi)始地方是編寫(xiě)一個(gè)在列表中查找最小項(xiàng)的方法。與 Sort.sort 一樣,我們將在完成方法之前先編寫(xiě)一個(gè)測(cè)試。首先,我們將創(chuàng)建一個(gè)簡(jiǎn)單的 findSmallest 方法,它只是返回某個(gè)任意的值:

顯然,這不是一個(gè)正確的實(shí)現(xiàn),但我們選擇在編寫(xiě)測(cè)試之前先不考慮 findSmallest 的實(shí)現(xiàn)。使用 org.junit 庫(kù),我們很容易將此測(cè)試添加到我們的 TestSort 類(lèi)中,如下所示:

和 TestSort.testSort 一樣,我們運(yùn)行我們的 TestSort.testFindSmallest 方法,以確保它失敗。當(dāng)我們運(yùn)行這個(gè)測(cè)試時(shí),我們會(huì)看到它實(shí)際上通過(guò)了,即沒(méi)有出現(xiàn)任何消息。這是因?yàn)槲覀儎偤糜簿幋a了正確的返回值 x[2]。讓我們修改我們的 findSmallest 方法,使其返回一個(gè)明顯不正確的值:

進(jìn)行了這個(gè)更改后,當(dāng)我們運(yùn)行 TestSort.testFindSmallest 時(shí),我們將得到一個(gè)錯(cuò)誤,這是一件好事:

和以前一樣,我們給自己設(shè)了一個(gè)小游戲,我們的目標(biāo)現(xiàn)在是修改 Sort.findSmallest 的代碼,以使這個(gè)錯(cuò)誤不再出現(xiàn)。這個(gè)目標(biāo)比使 Sort.sort 工作更容易一些,可能也更容易上癮。

注意:我好像故意硬編碼了正確的返回值 x[2],這看起來(lái)有些別扭。但當(dāng)我錄制這個(gè)講座視頻時(shí),我確實(shí)做了這個(gè)無(wú)意識(shí)的錯(cuò)誤!

接下來(lái),我們將解決真正編寫(xiě) findSmallest 方法。這似乎應(yīng)該相對(duì)簡(jiǎn)單。如果你是一個(gè) Java 初學(xué)者,你可能會(huì)寫(xiě)出類(lèi)似下面這樣的代碼:

然而,這將導(dǎo)致編譯錯(cuò)誤 "無(wú)法將 < 運(yùn)算符應(yīng)用于 'java.lang.String'"。問(wèn)題在于 Java 不允許使用 < 運(yùn)算符比較字符串。

當(dāng)你在編程過(guò)程中遇到這種容易描述的問(wèn)題時(shí),最好使用搜索引擎。例如,我們可以使用谷歌搜索“java 字符串比較小于”,這樣的搜索結(jié)果可能會(huì)包含像 這個(gè): https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java 的 Stack Overflow 帖子。

這篇帖子中的一個(gè)受歡迎答案解釋了 str1.compareTo(str2) 方法的工作原理:如果 str1 < str2,該方法將返回一個(gè)負(fù)數(shù);如果它們相等,則返回0;如果 str1 > str2,則返回一個(gè)正數(shù)。

將這一點(diǎn)融入到我們的代碼中,我們可能得到:

注意我們?cè)诖a中使用了 @source 標(biāo)簽,以引用我們的來(lái)源。我為那些正式學(xué)習(xí) 61B 的人使用這個(gè)例子,這不是真實(shí)世界的典型做法。

由于我們?cè)谑褂萌碌恼Z(yǔ)法功能,我們可能對(duì) findSmallest 方法的正確性缺乏自信。幸運(yùn)的是,我們剛剛寫(xiě)了那個(gè)測(cè)試不久之前。如果我們嘗試運(yùn)行它,我們會(huì)發(fā)現(xiàn)沒(méi)有任何輸出,這意味著我們的代碼可能是正確的。

為了增加我們的信心,可以通過(guò)添加更多的測(cè)試用例來(lái)增加我們的信心。例如,我們可以更改 testFindSmallest 如下所示:

重新運(yùn)行測(cè)試,我們將看到它仍然通過(guò)了。雖然我們并不能完全確定它是否正確,但我們比沒(méi)有任何測(cè)試時(shí)更有把握了。

Swap 交換

看一下下面的sort方法,我們需要寫(xiě)的下一個(gè)輔助方法是將一個(gè)元素移到數(shù)組前面,我們稱(chēng)之為swap。

寫(xiě)一個(gè)swap方法非常簡(jiǎn)單,你可能之前已經(jīng)做過(guò)了。一個(gè)正確的實(shí)現(xiàn)可能如下所示:

然而,為了展示測(cè)試的作用,讓我們引入一個(gè)有意的錯(cuò)誤。一個(gè)不太熟悉的程序員可能會(huì)這樣寫(xiě):

通過(guò)使用JUnit輔助方法,編寫(xiě)一個(gè)針對(duì)這個(gè)方法的測(cè)試非常容易。下面是一個(gè)樣例測(cè)試。需要注意的是,我們還修改了主方法,讓它調(diào)用testSwap而不是testFindSmallest或testSort。

對(duì)我們這個(gè)有錯(cuò)誤的swap方法運(yùn)行這個(gè)測(cè)試,會(huì)得到一個(gè)錯(cuò)誤,這是我們預(yù)期的。

值得注意的是,我們只調(diào)用了testSwap而沒(méi)有調(diào)用testSort,如果我們的main方法如下所示,當(dāng)testSort失敗時(shí),整個(gè)main方法都會(huì)終止執(zhí)行,testSwap將永遠(yuǎn)不會(huì)運(yùn)行:

在本章的最后,我們將學(xué)習(xí)一種更優(yōu)雅的處理多個(gè)測(cè)試的方法,它將避免手動(dòng)指定要運(yùn)行的測(cè)試的需要。

現(xiàn)在我們有了一個(gè)失敗的測(cè)試,我們可以用它來(lái)幫助我們調(diào)試。一種方法是在swap方法內(nèi)設(shè)置一個(gè)斷點(diǎn),并在IntelliJ中使用可視化的調(diào)試功能。如果你想要了解更多關(guān)于調(diào)試的信息和實(shí)踐,可以參考<a href="https://sp19.datastructur.es/materials/lab/lab3/lab3">Lab3:</a>?。通過(guò)逐行調(diào)試代碼,很容易理解出問(wèn)題所在(可以觀(guān)看視頻或自己嘗試),然后我們可 以通過(guò)在這一節(jié)開(kāi)始時(shí)添加一個(gè)臨時(shí)變量來(lái)修復(fù)代碼:

再次運(yùn)行測(cè)試,我們將會(huì)看到測(cè)試通過(guò)了。

修改findSmallest

現(xiàn)在我們已經(jīng)有了多個(gè)方法的片段,我們可以開(kāi)始嘗試將它們連接在一起以創(chuàng)建Sort方法。

很明顯,我們可以使用findSmallest和swap方法,但當(dāng)我們這樣做時(shí)就會(huì)立即意識(shí)到存在一個(gè)不匹配的問(wèn)題:findSmallest返回一個(gè)字符串,而swap方法需要兩個(gè)索引。

換句話(huà)說(shuō),findSmallest應(yīng)該返回的是最小字符串的索引,而不是字符串本身。出現(xiàn)這種錯(cuò)誤是很正常的,而且很容易發(fā)生,所以如果你發(fā)現(xiàn)自己也這樣做了,不要擔(dān)心。在編寫(xiě)代碼的過(guò)程中,反復(fù)修改設(shè)計(jì)是很正常的。

幸運(yùn)的是,這個(gè)新設(shè)計(jì)可以很容易地修改。我們只需要調(diào)整findSmallest,讓它返回一個(gè)int,如下所示:

由于這是一個(gè)非常重大的改變,我們還應(yīng)該更新testFindSmallest,并確保findSmallest仍然有效。

在修改TestSort以便運(yùn)行這個(gè)測(cè)試,并運(yùn)行TestSort.main后,我們看到我們的代碼通過(guò)了測(cè)試?,F(xiàn)在,我們可以繼續(xù)修改sort方法,填入排序算法的前兩個(gè)步驟。

現(xiàn)在只剩下一步了,即如何使用遞歸選擇排序剩下的元素。我們將在下一節(jié)中解決這個(gè)問(wèn)題。

回顧我們已經(jīng)完成的工作,值得注意的是,我們?cè)趯?shí)際方法之前創(chuàng)建了測(cè)試,并在使用這些測(cè)試之前用它們來(lái)建立對(duì)實(shí)際方法的信心。這是一個(gè)非常重要的思想,如果你決定采用這種方式,它將對(duì)你有很大的幫助。

遞歸輔助方法

在本節(jié)開(kāi)始時(shí),考慮一下如何進(jìn)行遞歸調(diào)用,以完成sort方法:

對(duì)于你們中那些習(xí)慣了使用類(lèi)似Python這樣的語(yǔ)言的人來(lái)說(shuō),可能會(huì)嘗試使用類(lèi)似切片表示法的方法,比如

然而,在Java中沒(méi)有一個(gè)可以引用一個(gè)子數(shù)組的概念,也就是說(shuō),我們不能只傳遞數(shù)組的下一個(gè)項(xiàng)的地址。

需要考慮的是,需要考慮一個(gè)較大數(shù)組的子集是一種非常常見(jiàn)的問(wèn)題。一個(gè)典型的解決方法是創(chuàng)建一個(gè)私有的輔助方法,這個(gè)方法有一個(gè)額外的參數(shù)(或多個(gè)參數(shù)),用來(lái)確定需要考慮的數(shù)組的哪一部分。例如,我們可以編寫(xiě)一個(gè)稱(chēng)為sort的私有輔助方法,該方法只考慮從位置start開(kāi)始的項(xiàng)。

與我們的公共sort方法相比,現(xiàn)在使用遞歸會(huì)相對(duì)簡(jiǎn)單一些,因?yàn)槲覀兌嗔艘粋€(gè)名為start的額外參數(shù)。下面是一個(gè)使用遞歸的示例。在下一節(jié)中,我們將對(duì)這個(gè)方法進(jìn)行測(cè)試。

現(xiàn)在我們有了一個(gè)輔助方法,我們需要設(shè)置正確的原始調(diào)用。如果我們將開(kāi)始位置設(shè)置為0,我們就可以對(duì)整個(gè)數(shù)組進(jìn)行排序。

當(dāng)你在試圖對(duì)一個(gè)本質(zhì)上不是遞歸的數(shù)據(jù)結(jié)構(gòu)使用遞歸時(shí),這種方法非常常見(jiàn),比如數(shù)組。

調(diào)試和完成Sort方法

運(yùn)行我們的testSort方法,我們立即遇到了一個(gè)問(wèn)題:

使用Java調(diào)試器,我們可以看到問(wèn)題是start不斷增加,變成了4。仔細(xì)地逐行調(diào)試代碼(參見(jiàn)上面的視頻),我們發(fā)現(xiàn)問(wèn)題在于我們?cè)谶f歸sort方法中忘記了包含一個(gè)基本情況。修復(fù)這個(gè)問(wèn)題非常簡(jiǎn)單:

重新運(yùn)行這個(gè)測(cè)試,我們?cè)俅蔚玫揭粋€(gè)錯(cuò)誤:

再次使用IntelliJ調(diào)試器進(jìn)行恰當(dāng)?shù)恼{(diào)試(請(qǐng)參見(jiàn)視頻),我們可以確定一行代碼的結(jié)果與預(yù)期不符。需要注意的是,我在比你可能更高級(jí)的抽象層次上調(diào)試代碼,這是通過(guò)使用“跳過(guò)”比“進(jìn)入”更多地使用Step Over來(lái)實(shí)現(xiàn)的。如在Lab 3中討論的,以更高的抽象級(jí)別進(jìn)行調(diào)試可以節(jié)省大量的時(shí)間和精力,因?yàn)檫@樣你可以比較整個(gè)函數(shù)調(diào)用的結(jié)果與你的預(yù)期值。

具體來(lái)說(shuō),我們發(fā)現(xiàn)在對(duì)輸入{"an", "have", "i", "egg"}進(jìn)行排序時(shí),當(dāng)排序剩下的3個(gè)(共4個(gè))項(xiàng)時(shí),findSmallest方法給出的是第0個(gè)項(xiàng)("an"),而不是第3個(gè)項(xiàng)("egg")。仔細(xì)看看findSmallest的定義,不難發(fā)現(xiàn),由于findSmallest看的是整個(gè)數(shù)組而不只是從start位置開(kāi)始的項(xiàng),所以這個(gè)行為并不令人意外。這種設(shè)計(jì)缺陷非常常見(jiàn),編寫(xiě)測(cè)試并使用調(diào)試器來(lái)修復(fù)它們是一個(gè)很好的方法。

為了修復(fù)我們的代碼,我們將findSmallest修改為接受第二個(gè)參數(shù)start,即findSmallest(String[] x, int start)。這樣,我們確保只在未排序的項(xiàng)中找到最小項(xiàng)。修改后的代碼如下所示:

由于我們對(duì)一個(gè)基本模塊進(jìn)行了重大更改,即findSmallest,我們應(yīng)該確保我們的更改是正確的。

首先,我們修改了testFindSmallest,使它使用我們的新參數(shù),如下所示:

然后,我們修改了TestSort.main,以便運(yùn)行testFindSmallest。這個(gè)測(cè)試通過(guò)了,強(qiáng)烈暗示我們對(duì)findSmallest的修改是正確的。

接下來(lái),我們修改了Sort.sort,使它在findSmallest中使用新的start參數(shù):

然后,我們修改了TestSort,使它運(yùn)行TestSort.sort,好了,這個(gè)方法可以工作了。我們完成了!你現(xiàn)在已經(jīng)看到了這節(jié)講座一開(kāi)始的“新方法”,我們將在本章的剩余部分反思這個(gè)方法。

開(kāi)發(fā)過(guò)程反思

當(dāng)你編寫(xiě)和調(diào)試程序時(shí),你經(jīng)常會(huì)發(fā)現(xiàn)自己在不同的上下文之間切換。試圖一次記住太多的東西,最終會(huì)導(dǎo)致災(zāi)難性的后果,或者最好情況下進(jìn)展緩慢。

擁有一組自動(dòng)化測(cè)試有助于減少這種認(rèn)知負(fù)擔(dān)。例如,當(dāng)我們意識(shí)到findSmallest中存在一個(gè)bug時(shí),我們可以切換到考慮findSmallest并使用我們的testFindSmallest方法來(lái)確定它是否正確,然后再切換回sort。這與一種更幼稚的方法形成了鮮明對(duì)比,你只會(huì)一遍又一遍地調(diào)用sort,然后嘗試推斷出findSmallest方法是否正確。

打個(gè)比方,你可以通過(guò)上飛機(jī)、起飛、跳傘、拉動(dòng)降落傘繩索并看看降落傘是否打開(kāi)來(lái)測(cè)試降落傘繩索是否有效。然而,你也可以在地面上拉一下繩索看看會(huì)發(fā)生什么。同樣地,使用sort來(lái)嘗試findSmallest是不必要的。

正如本章的開(kāi)頭所提到的,測(cè)試還可以幫助您對(duì)程序的基本部分建立信心,所以如果出現(xiàn)問(wèn)題,您就可以更好地了解從哪里開(kāi)始解決。

最后,測(cè)試使得重構(gòu)代碼變得更容易。假設(shè)您決定重寫(xiě)findSmallest,使其更快或更易讀。我們可以安全地進(jìn)行修改,然后查看測(cè)試是否仍然工作。

  • 更好的JUnit

    首先,讓我們回顧一下我們今天所見(jiàn)到的新語(yǔ)法,即 org.junit.Assert.assertEquals(expected, actual)。這個(gè)方法(有一個(gè)非常長(zhǎng)的名字)測(cè)試 expected 和 actual 是否相等,如果它們不相等,則用一個(gè)詳細(xì)的錯(cuò)誤消息終止程序。

    JUnit 除了 assertEquals 之外還有許多類(lèi)似的方法,比如 assertFalse、assertNotNull、fail 等等,它們可以在官方的 JUnit文檔中找到。JUnit 還有許多其他復(fù)雜的功能,在61B中我們不會(huì)描述或教授,但你可以自由使用它們。

    雖然JUnit無(wú)疑改進(jìn)了很多問(wèn)題,但我們之前的測(cè)試代碼在幾個(gè)方面都有些笨拙。在本節(jié)的剩余部分,我們將討論兩個(gè)主要的增強(qiáng)功能,以使您的代碼更清晰、更易于使用。從語(yǔ)法的角度來(lái)看,這些增強(qiáng)功能似乎非常神秘,所以現(xiàn)在只需復(fù)制我們所做的,以后我們會(huì)在后面的章節(jié)中解釋其中的一些(但不是全部)。

    第一個(gè)增強(qiáng)功能是使用被稱(chēng)為 "測(cè)試注釋 "的功能。為此,我們需要:

    一旦我們完成了這三步,如果我們使用 Run->Run 命令在 JUnit 中重新運(yùn)行我們的代碼,所有的測(cè)試都將自動(dòng)執(zhí)行,無(wú)需手動(dòng)調(diào)用。這種基于注釋的方法有幾個(gè)優(yōu)點(diǎn):

    第二個(gè)增強(qiáng)功能允許我們?yōu)橐恍┓浅H唛L(zhǎng)的方法名稱(chēng)以及注釋名稱(chēng)使用較短的名稱(chēng)。具體來(lái)說(shuō),我們將使用被稱(chēng)為 "導(dǎo)入語(yǔ)句 "的功能。

    首先,在文件的頂部添加導(dǎo)入語(yǔ)句 import org.junit.Test;。這樣做后,我們可以將所有的 @org.junit.Test 替換為簡(jiǎn)單的 @Test。

    然后,我們添加第二個(gè)導(dǎo)入語(yǔ)句 import static org.junit.Assert.*。這樣做后,我們可以省略任何地方的 org.junit.Assert.。例如,我們可以將 org.junit.Assert.assertEquals(expected2, actual2); 替換為簡(jiǎn)單的assertEquals(expected2, actual2);。

    關(guān)于導(dǎo)入語(yǔ)句的原因我們將在以后的課程中詳細(xì)解釋?,F(xiàn)在,只需要使用和享受它。

    測(cè)試哲學(xué)

    正確性工具1: 自動(dòng)打分機(jī)

    讓我們回到零點(diǎn)。自動(dòng)打分機(jī)很可能是你接觸到的第一個(gè)正確性工具。實(shí)際上,我們的自動(dòng)打分機(jī)是基于 JUnit 加上一些額外的自定義庫(kù)。

    自動(dòng)打分機(jī)有一些很大的好處。可能最重要的是,它為你驗(yàn)證了正確性,為你節(jié)省了寫(xiě)測(cè)試的繁瑣和無(wú)指導(dǎo)性的任務(wù)。它還通過(guò)給予豐厚的分?jǐn)?shù)作為正確性的激勵(lì)來(lái)使評(píng)估過(guò)程充滿(mǎn)樂(lè)趣。不過(guò),如果學(xué)生花費(fèi)過(guò)多的時(shí)間追逐最后的分?jǐn)?shù),這可能也會(huì)適得其反,因?yàn)檫@些分?jǐn)?shù)實(shí)際上并不會(huì)影響他們的成績(jī)或?qū)W習(xí)。

    然而,自動(dòng)打分機(jī)在現(xiàn)實(shí)世界中是不存在的,依賴(lài)于自動(dòng)打分機(jī)可能會(huì)養(yǎng)成不好的習(xí)慣。通過(guò)偶爾上傳你的代碼并等待自動(dòng)打分機(jī)運(yùn)行來(lái)妨礙了你的工作流程。自動(dòng)打分機(jī)驅(qū)動(dòng)的開(kāi)發(fā)(Autograder Driven Development) 就是這種情況的一個(gè)極端版本,在這種情況下,學(xué)生在寫(xiě)所有的代碼、修復(fù)編譯錯(cuò)誤之后再提交到自動(dòng)打分機(jī)。在收到錯(cuò)誤后,學(xué)生可能會(huì)嘗試進(jìn)行一些更改,添加一些打印語(yǔ)句,然后再次提交。然后再重復(fù)以上步驟。如果你依賴(lài)于自動(dòng)打分機(jī),你既不能控制你的工作流程,也不能控制你的代碼。

    正確性工具2: JUnit 測(cè)試

    正如我們所見(jiàn),JUnit 測(cè)試為您打開(kāi)了一個(gè)新的世界。與依賴(lài)于其他人編寫(xiě)的自動(dòng)打分機(jī)不同,您為程序的每個(gè)部分編寫(xiě)測(cè)試。我們把這些部分稱(chēng)為一個(gè)單元。這樣可以讓您對(duì)代碼的每個(gè)單元都有信心-您可以依賴(lài)它們。這也有助于減少調(diào)試時(shí)間,因?yàn)槟梢詫⒆⒁饬性谝欢未a(通常是一個(gè)方法)上。單元測(cè)試還可以迫使您澄清每個(gè)代碼單元應(yīng)該完成什么任務(wù)。

    然而,單元測(cè)試也有一些不足之處。首先,編寫(xiě)全面的測(cè)試需要時(shí)間。很容易編寫(xiě)不完整的單元測(cè)試,這給您的代碼帶來(lái)虛假的信心。編寫(xiě)依賴(lài)于其他單元的單元測(cè)試也很困難(考慮一下您的 LinkedListDeque 中的 addFirst 方法)。

    *測(cè)試驅(qū)動(dòng)開(kāi)發(fā)(TDD)*

    TDD 是一種在編寫(xiě)代碼之前先編寫(xiě)代碼測(cè)試的開(kāi)發(fā)過(guò)程。步驟如下:

    在本課程中,不要求使用測(cè)試驅(qū)動(dòng)開(kāi)發(fā),也許這不是你的風(fēng)格,但是總的來(lái)說(shuō),單元測(cè)試絕對(duì)是一個(gè)好主意。

    正確性工具3: 集成測(cè)試

    單元測(cè)試非常好,但我們也應(yīng)該確保這些單元正確地一起工作。集成測(cè)試驗(yàn)證組件之間的正確交互。實(shí)際上,JUnit 就可以用于這個(gè)目的。你可以將單元測(cè)試看作是最詳細(xì)的測(cè)試,而集成測(cè)試則是對(duì)此的抽象水平。

    集成測(cè)試的挑戰(zhàn)在于它很繁瑣,手動(dòng)進(jìn)行測(cè)試很繁瑣,但自動(dòng)化測(cè)試又很具有挑戰(zhàn)性。在高度抽象的水平上,很容易忽略細(xì)微或罕見(jiàn)的錯(cuò)誤。

    總結(jié)一下,你應(yīng)該一定要編寫(xiě)測(cè)試,但只有當(dāng)它們可能是有用的時(shí)候才編寫(xiě)!從 TDD 中獲得靈感,先編寫(xiě)測(cè)試,然后再編寫(xiě)代碼,在某些情況下這也是非常有幫助的。

    下一步是什么?

    • Project1b


【reading】【中文】 3.1 A New Way的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
广昌县| 漳平市| 罗山县| 三门峡市| 兴仁县| 蕉岭县| 济南市| 盐池县| 保靖县| 万盛区| 九江市| 沧州市| 石泉县| 荥阳市| 湖北省| 内乡县| 文登市| 枣庄市| 东乌| 外汇| 金溪县| 甘谷县| 青阳县| 江达县| 公主岭市| 文山县| 洛浦县| 于都县| 阿勒泰市| 南靖县| 遵义市| 木里| 黑龙江省| 鄂伦春自治旗| 兖州市| 伊金霍洛旗| 德庆县| 富阳市| 惠东县| 岳西县| 田阳县|