接口與單元測試隨想
剛才看到一則關于TDD的新聞,挺雷的......然后又想起以前跟別人解釋關于為什么在Spring里需要先寫個接口XXXInterface,然后再寫實現類XXXInterfaceImpl的問題。寫一點自己的想法,關于單元測試。
一個情景:
一個User類,提供一個靜態方法:(這里不討論框架或者異常控制流程的正確性)
public class User{ public static User login(String username,String password) throw LoginException{ |
下面討論如何對這個方法進行測試:
單純對于這個模塊進行單元測試:
public class UserTest{ public void testLogin(){ |
這樣的測試,正確性和速度實際上都保證不了。因為login中引入了數據庫的各種操作,各種未知的可能性都是存在的。比如說數據庫并未配置正確或者數據庫當前無法訪問,直接會導致這個測試失敗,但測試失敗并不意味著User.login方法錯了。同時,由于訪問數據庫造成的速度可能使這么一個簡單的測試需要幾百毫秒甚至幾秒,那么大量的測試用例加在一起,如文中提到的花費個幾十分鐘是絕對可能的。
實際上這個簡單的測試方案違背了單元測試的基本原則:單元測試應該測試獨立的單元模塊,這個單元不應依賴于其他模塊。在這里顯然這個Login的方法使用DAO中的一些方法。
下面討論DAO:
public class UserDAO implements DAO<User>{ public class DAOFactory{ public static DAOFactory getInstance(){ |
一般來說DAO部分都跟上面的差不多(或許是直接注入進User的,但實際原理是一致的):一共兩個步驟:1、獲取DAO;2、使用DAO。為了不讓User的測試受到DAO部分的干擾,就需要使用Mock技術,對DAO對象進行模擬,保證其各種方法的正確性。然后當User類需要獲取DAO時,將MockUserDAO代替UserDAO交給它。
public class MockUserDAO implements DAO<User>{ //肯定準確的實現 } |
而DAOFactory由于是單例,其方法getInstance是靜態的,所以最后只能靠修改原始代碼來實現獲得另一個工廠——也就是MockDAOFactory。如果在程序員和單元測試人員不是同一個人的時候,真的是非常麻煩的事情..... (從這個角度上將,我極力反對靜態方法)雖說這種情形可以靠反射來進行偽造實例的活動,但是這種解決方案總是有一種黑客的感覺....
另外就是如果DAO不是接口,而只有實現(這并不是不可能的情況,在有通用DAO的前提下,完全可以達到),情況也會很麻煩。由于DAO不是接口,導致無法Mock這個DAO。也許可以使用MockDAO extends DAO的方案,但也許在DAO的構造方法中依舊有著連接數據庫,初始化連接池,初始化日志等等的初始化過程,由于其在構造方法中,是無法覆蓋掉的。在這種情況下,就只能通過重構來實現測試了。(這也就是即使只有一個實現,也要盡量寫一個接口的原因)
單元測試是至關重要的,我個人認為,如果一個團隊中的程序員頭腦都不錯,那么包括getter和setter都應該測試。單元測試的度基本上可以說是寧濫勿缺的。
挺雜亂的,不過只是隨想,所以也無所謂。
原文鏈接:http://my.oschina.net/Jeky/blog/30354
posted on 2013-05-08 10:34 順其自然EVO 閱讀(561) 評論(0) 編輯 收藏 所屬分類: 敏捷測試