例如,您可能更喜歡編寫經典的單元測試,通過檢查返回值來單獨測試對象的行為。 您可能會喜歡經典存根或偽造的物品; 或者您可能喜歡使用模擬對象模擬角色,甚至使用模擬對象作為存根。 這個博客以及我接下來的幾篇博客都采用了一種非常非常通用的設計模式,并研究了可以采用的不同測試方法。
我正在使用的設計模式顯示在下面的UML圖中,這是我以前使用過的,主要是因為它是如此普遍。 您可能不喜歡它-它的設計更像是“問不說”而不是“告訴不問”,但是它適合這個簡單的演示。

在此示例中,上面的普遍模式將用于從數據庫中檢索和驗證地址。 該示例代碼可從我的GitHub存儲庫中獲得 ,它以一個簡單的Spring MVC webapp為起點,并使用一個小型MySQL數據庫來存儲地址,其原因無非是我已經在筆記本電腦上本地運行了服務器。
就測試而言,博客將集中于測試服務層組件AddressService:
@Component
public class AddressService {private static final Logger logger = LoggerFactory.getLogger(AddressService.class);private AddressDao addressDao;/*** Given an id, retrieve an address. Apply phony business rules.* * @param id* The id of the address object.*/public Address findAddress(int id) {logger.info("In Address Service with id: " + id);Address address = addressDao.findAddress(id);businessMethod(address);logger.info("Leaving Address Service with id: " + id);return address;}private void businessMethod(Address address) {logger.info("in business method");// Do some jiggery-pokery here....}@Autowiredvoid setAddressDao(AddressDao addressDao) {this.addressDao = addressDao;}}
…如上面的代碼所示,您可以看到它非常簡單:它具有findAddress(…)方法,該方法將單個地址的ID(或表主鍵)作為輸入。 它調用數據訪問對象(DAO),并假裝在將Address對象返回給調用者之前進行一些業務處理。
public class Address {private final int id;private final String street;private final String town;private final String country;private final String postCode;public Address(int id, String street, String town, String postCode, String country) {this.id = id;this.street = street;this.town = town;this.postCode = postCode;this.country = country;}public int getId() {return id;}public String getStreet() {return street;}public String getTown() {return town;}public String getCountry() {return country;}public String getPostCode() {return postCode;}
}
如上所述,我將介紹測試該代碼的不同策略,其中一些我保證您會討厭。 第一個仍然被許多開發人員和組織廣泛使用的是……
不要寫任何測試
令人難以置信的是,某些人和組織仍在這樣做。 他們編寫代碼,將其部署到Web服務器并打開一個頁面。 如果頁面打開,則他們將發送代碼;如果頁面未打開,則他們將修復代碼,對其進行編譯,重新部署,重新加載Web瀏覽器并重新測試。
我見過的關于該技術的最極端的例子:幾年前,在一個著名的政府項目中,更改代碼,部署到服務器,運行代碼,發現錯誤并再次循環。 我猜想,為了節省資金,分包商從“離岸”公司引進了一批廉價且缺乏經驗的程序員,并且沒有足夠的經驗豐富的程序員來指導他們。 所討論的模塊是一個基于Spring的簡單消息驅動Bean,它從一個隊列中獲取消息,應用了一些業務邏輯,然后將其推入另一個隊列:簡單隊列。 最初的作者通過編寫一些測試開始,然后將代碼傳遞給其他沒有經驗的團隊成員。 當代碼更改并且測試失敗時,他們只是關閉了所有測試。 測試包括將MDB部署到EJB容器(Weblogic),將消息推送到系統的前端,觀察來自另一端的消息并調試整個過程中的日志。 您可能會說這樣的端到端測試還不錯,但是部署MDB和運行測試只花了一個小時:在一個工作日內,這是8個代碼更改。 發展不完全Swift!
我的工作? 修復過程和代碼。 解決方案? 編寫測試,運行測試并重構代碼。 該模塊從零測試變成了大約40個單元測試和一些集成測試,并且經過改進并最終交付。 做完了
大多數人會對這種技術有自己的看法,而我的看法是:它產生了不可靠的代碼; 使用此技術需要花費更長的時間編寫和交付代碼,因為您花費大量時間等待服務器啟動,部署WAR / EJB等。并且,通常由經驗不足的程序員使用,或者沒有使用過此功能的程序員通常會使用它技術–您確實遭受了痛苦。 我可以說我從事的項目是編寫測試的項目,而其他開發人員則不在。 測試團隊在我的代碼中發現的bug很少,而其他開發人員正在修復大量的bug,并瘋狂地努力按時完成任務。 我是一個出色的程序員,還是編寫測試能帶來收益? 根據經驗,如果您使用此技術,則會有很多其他錯誤要修復,因為您無法輕松,重復地測試與您開發的故事相伴的多種場景。 這是因為它花費的時間太長,您必須記住每種情況,然后手動運行它們。
我確實想知道,不寫測試技術是否比1960年代的計算技術昂貴時留下的宿醉,您必須手動在打Kong卡或紙帶上編寫程序,然后使用“真值表”進行目視檢查。 當您對自己的代碼工作感到滿意后,便將其發送到計算機室并運行您的代碼-我還不算老,無法記住60年代的計算。 機器時間昂貴的事實意味著自動化測試是不可能的。 盡管計算機的速度越來越快,但這種過時的范例仍在繼續,退化為一種模式,您錯過了勤奮的精神檢查,只是運行了代碼,如果代碼破了,您就將其修復。 這種退化的范式仍在學校,學院和書籍中教授,直到近幾年才受到挑戰。
這就是為什么很難說服人們改變他們的習慣嗎?
該技術的另一個主要問題是項目可能會陷入癱瘓狀態。 就像我在上面說的那樣,使用這種技術,您的錯誤數將很高,并且給項目經理帶來不好的印象,使他們認為代碼會發臭并強制執行以下想法:除非絕對必要,否則不要更改代碼,因為這可能會破壞某些東西。 經理常常對授權代碼更改不滿意,他們通常不信任開發人員并對其進行微觀管理。 確實,開發人員自己對添加代碼更改非常猶豫,因為破壞某些內容會使他們看起來很糟糕。 他們所做的更改盡可能的小,并且沒有任何重構。 隨著時間的流逝,這會加劇混亂,并且代碼的退化甚至會變得更大。
雖然我認為您應該加載并查看頁面以確保所有功能都正常運行,但是只有在有大量測試告訴您代碼可以正常運行時,才應該在故事的結尾進行操作。
我希望當我總結這種方法很糟糕的時候(盡管時間會證明一切)時,我不會引起爭議。 您可能還想知道為什么要包含它,原因是要指出它很爛,并在下面的博客中提供了一些替代方法。
參考: 測試技術–第1部分–不通過JCG合作伙伴
在Captain Debug博客上 編寫測試 。相關文章 :
- 端到端測試的濫用–測試技術2
- 您應該對什么進行單元測試? –測試技術3
- 常規單元測試和存根–測??試技術4
- 使用模擬的單元測試–測試技術5
- 為舊版代碼創建存根–測試技術6
- 有關為舊版代碼創建存根的更多信息–測試技術7
- 為什么要編寫單元測試–測試技巧8
- 一些定義–測試技術9
- 使用FindBugs產生更少的錯誤代碼
- 在云中開發和測試
翻譯自: https://www.javacodegeeks.com/2011/11/testing-techniques-not-writing-tests.html