不要单元测试错误
在進入標題主題之前,我們有一個簡單的編程示例。 在編程任務中,我將演示一些不良的編碼樣式,并以此為基礎,我將更容易解釋為什么在單元測試中相同的樣式是不良的。 好吧,既然我寫了這句話,這似乎是一個顯而易見的陳述。 當編程不好時,為什么有些東西會在單元測試中好呢? 一件事是, 并非總是那樣 ,而另一件事是,當我們創建單元測試時,相同的錯誤可能并不那么明顯。
演示任務
演示任務非常簡單。 讓我們編寫一個類來確定整數> 1是否為質數。 該算法很簡單。 檢查以2開頭的所有數字,直到該數字的平方根為止。 如果數字不是素數,我們將找到一個將整數除以整數的數字;如果找不到除數,則數字是素數。
public class PrimeDecider {final int number;public PrimeDecider(int number) {this.number = number;}public boolean isPrime() {for (int n = 2; n * n < number; n++) {if (number % n == 0) {return false;}}return true;} }單元測試是
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue;import org.junit.Test;public class PrimDeciderTest {@Testpublic void sample_2_IsPrime() {PrimeDecider decider = new PrimeDecider(2);boolean itIsPrime = decider.isPrime();assertTrue(itIsPrime);}@Testpublic void sample_17_IsPrime() {PrimeDecider decider = new PrimeDecider(17);boolean itIsPrime = decider.isPrime();assertTrue(itIsPrime);}@Testpublic void sample_10_IsNotPrime() {PrimeDecider decider = new PrimeDecider(10);boolean itIsPrime = decider.isPrime();assertFalse(itIsPrime);} }這是一個很好的測試,可讀性強,有一些復制粘貼,并且最重要的是它為我們提供了100%的代碼覆蓋率。 相信我:
全是綠色的。 沒錯! 我們開心。
出現錯誤
然而,有一天,有人想到了一個奇怪的想法來測試9是否為質數。 信不信由你,我們的程序說9是質數。 因此,測試人員(或者,如果您不是很幸運的客戶)會打開一個故障單:
BGTCKT17645329-KT對于與3相乘的數字,Prime方法無法給出正確的答案。 例如,對于表示9的對象,結果為true。
然后是錯誤修復的繁瑣工作。 通常是多么快樂。 首先,您克服了那種耳目一新的感覺,即“客戶是愚蠢的”。 顯然,客戶是愚蠢的,因為他想使用該類來測試9,這本來就不是……哈哈! 并且因為錯誤描述根本是錯誤的。 沒有方法Prime ! 并且代碼正確地檢測到例如數字3(它本身是3的乘法)是質數。 并且它還正確檢測出6和12不是質數。 因此,客戶如何敢于制作這樣的錯誤報告。 這樣的想法可能會幫助您冷靜下來,但對業務沒有幫助,這是像您這樣的專業人員的首要任務。
冷靜下來后,您承認該代碼實際上不適用于數字9,因此您開始調試和修復它。 首先是失敗的單元測試。 那就是我們要做TDD的方式:
@Testpublic void demonstrationOf_BGTCKT17645329() {PrimeDecider decider = new PrimeDecider(9);boolean itIsPrime = decider.isPrime();assertFalse(itIsPrime);}然后您提供了修復程序:
public boolean isPrime() {if (number == 9)return false;for (int n = 2; n * n < number; n++) {if (number % n == 0) {return false;}}return true;}我只是在開玩笑!
實際上,我已經在實際的生產代碼中看到了類似的修復程序。 當您承受時間壓力并且生活有限時,即使您知道適當的解決方案,也可能會提出類似的解決方案。 在這種情況下,只需簡單地在循環條件中的<符號前面插入a =即可測試該數字實際上不是素數的平方。 本質上是代碼
for (int n = 2; n * n =< number; n++) {會好的。
在實際的生產情況下,這可能是一個真實而龐大的重構,并且如果由于代碼通常用于小于25的數字而很少出現這些特殊情況,那么此修復在商業上是可以的。
實際修復錯誤
更現實一點,并假設您意識到問題不僅限于數字9,還包括所有平方數,然后應用此修復程序:
public class PrimeDecider {final int number;public PrimeDecider(int number) {this.number = number;}public boolean isPrime() {if (isASquareNumber(number))return false;for (int n = 2; n * n < number; n++) {if (number % n == 0) {return false;}}return true;}private boolean isASquareNumber(int number) {double d = Math.sqrt(number);return Math.floor(d) == d;} }這很丑,但是行得通。 包含數千行的上帝類的真實單詞代碼即使在重構后也不會比這更好。
完成了嗎 并不是的。 讓我們再次看一下單元測試。 它記錄了該代碼
sample 2 is prime sample 17 is prime sample 10 is not prime demonstration of BGTCKT17645329那并不是特別有意義,尤其是最后一行。 報告該錯誤(除了一些錯誤的陳述),指出數字9處理不當。 但是實際的錯誤是程序無法正確處理質數平方的數字。 如果您知道ITIL,則第一個是事件,第二個是問題。 我們為事件創建了單元測試,這很好,我們做到了。 它有助于調試。 但是,當我們確定問題所在時,在應用此修復程序之前,我們并未創建一個程序來測試該問題的修復程序。 這不是真正的TDD,因為對事件進行了單元測試,但我們并未創建它來測試修復程序。
適當的測試將使用類似以下的名稱
some sample square number is not prime(在方法名稱中使用適當的駱駝套),它將有一些平方數,例如9、25、36作為測試數據。
結論
修復錯誤時,請小心TDD。 您可能會錯誤地應用它。 TDD說在編寫代碼之前先編寫單元測試。 您編寫的單元測試將定義您要編碼的內容。 這不是演示該錯誤的單元測試。 您可以將其用作調試和查找根本原因的工具。 但這不是TDD的一部分。 當您知道要寫什么時,無論您急切要修改代碼:都要編寫將測試您要編寫的功能的單元測試。
這就是我想要在標題中暗示的意思:針對功能或功能更改編寫單元測試,以修復錯誤而不是錯誤。
翻譯自: https://www.javacodegeeks.com/2015/02/not-unit-test-bugs.html
總結
- 上一篇: linux网卡ip配置(linux网卡i
- 下一篇: 一类医疗器械生产备案流程代办(一类医疗器