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