常規單元測試和存根–測??試技術4

我的上一個博客是有關測試代碼的方法以及討論您要做和不需要進行測試的方法的一系列博客中的第三篇。 它基于我使用一種非常常見的模式從數據庫中檢索地址的簡單方案:

…并且我提出了這樣的想法:任何不包含任何邏輯的類都不需要進行單元測試。 在其中,我包括了我的數據訪問對象DAO,而不是對此類進行集成測試以確保其與數據庫協同工作。

今天的博客涵蓋編寫常規或經典的單元測試,該測試使用存根對象強制實現測試主題隔離。 我們將要測試的代碼再次是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);address = businessMethod(address);logger.info("Leaving Address Service with id: " + id);return address;}private Address businessMethod(Address address) {logger.info("in business method");// Apply the Special Case Pattern (See MartinFowler.com)if (isNull(address)) {address = Address.INVALID_ADDRESS;}// Do some jiggery-pokery here....return address;}private boolean isNull(Object obj) {return obj == null;}@Autowired@Qualifier("addressDao")void setAddressDao(AddressDao addressDao) {this.addressDao = addressDao;}
}

邁克爾·費瑟(Michael Feather)的書《有效使用舊版代碼》指出,在以下情況下,測試不是單元測試:

  1. 它與數據庫對話。
  2. 它通過網絡進行通信。
  3. 它涉及文件系統。
  4. 您必須對環境做一些特殊的事情(例如編輯配置文件)才能運行它。

為了遵守這些規則,您需要將測試對象與系統的其余部分隔離開來,這就是存根對象的所在。存根對象是注入到您的對象中的對象,用于在測試情況下替換實際對象。 馬丁·福勒(Martin Fowler)在他的論文《 莫克斯不是存根》中將存根定義為:

“存根提供對測試過程中進行的呼叫的固定答復,通常通常根本不響應測試中編程的內容。 存根還可以記錄有關呼叫的信息,例如電子郵件網關存根,它可以記住“已發送”的消息,或者僅記住“已發送”的消息數量。”

用一個單詞來描述存根非常困難,我可以選擇虛擬或偽造,但是有些替換對象稱為假人或偽造-也由Martin Fowler描述:

  • 虛擬對象會傳遞,但從未實際使用過。 通常它們僅用于填充參數列表。
  • 偽對象實際上具有有效的實現,但是通常采取一些捷徑,這使它們不適合生產(內存數據庫是一個很好的例子)。

但是,我看到過其他術語“偽造對象”的定義,例如Roy Osherove在《 The Art Of Unit Testing》一書中將偽造對象定義為:

  • 偽造品是一個通用術語,可用于描述存根或模擬對象……因為兩者看起來都像真實對象。

…因此,我和其他許多人一樣,傾向于將所有替換對象稱為模擬或存根,因為兩者之間存在差異,但稍后會更多。

在測試AddressService時 ,我們需要用存根數據訪問對象替換實際的數據訪問對象,在這種情況下,它看起來像這樣:

public class StubAddressDao implements AddressDao {private final Address address;public StubAddressDao(Address address) {this.address = address;}/*** @see com.captaindebug.address.AddressDao#findAddress(int)*/@Overridepublic Address findAddress(int id) {return address;}
}

注意存根代碼的簡單性。 它應該易于閱讀,可維護,并且不包含任何邏輯,并且需要自己進行單元測試。 編寫存根代碼后,接下來進行單元測試:

public class ClassicAddressServiceWithStubTest {private AddressService instance;@Beforepublic void setUp() throws Exception {/* Create the object to test *//* Setup data that's used by ALL tests in this class */instance = new AddressService();}/*** Test method for* {@link com.captaindebug.address.AddressService#findAddress(int)}.*/@Testpublic void testFindAddressWithStub() {/* Setup the test data - stuff that's specific to this test */Address expectedAddress = new Address(1, "15 My Street", "My Town","POSTCODE", "My Country");instance.setAddressDao(new StubAddressDao(expectedAddress));/* Run the test */Address result = instance.findAddress(1);/* Assert the results */assertEquals(expectedAddress.getId(), result.getId());assertEquals(expectedAddress.getStreet(), result.getStreet());assertEquals(expectedAddress.getTown(), result.getTown());assertEquals(expectedAddress.getPostCode(), result.getPostCode());assertEquals(expectedAddress.getCountry(), result.getCountry());}@Afterpublic void tearDown() {/** Clear up to ensure all tests in the class are isolated from each* other.*/}
}

請注意,在編寫單元測試時,我們的目標是清晰。 通常會犯一個錯誤,就是認為測試代碼不如生產代碼,從而導致測試代碼更加混亂且難以辨認。 單元測試的藝術中的 Roy Osherove提出了這樣的想法,即測試代碼應比生產代碼更具可讀性。 明確的測試應遵循以下基本的線性步驟:

  1. 創建被測對象。 在上面的代碼中,這是在setUp()方法中完成的,因為我正在對所有(一個)測試使用相同的被測對象。
  2. 設置測試。 這是在測試方法testFindAddressWithStub()中完成的,因為測試中使用的數據特定于該測試。
  3. 運行測試
  4. 撕毀測試。 這樣可以確保測試彼此隔離,并且可以按任何順序運行。

使用簡單的存根會產生將AddressService與外界隔離和快速運行測試的兩個好處。

這種測試有多脆? 如果您的要求改變了,那么測試和存根就會改變–畢竟不是那么脆弱嗎?

作為比較,我的下一個博客使用EasyMock重寫了該測試。

參考: 定期的單元測試和存根-來自JCG合作伙伴 的Captain Debug博客上的 測試技術4

相關文章 :

  • 測試技巧–不編寫測試
  • 端到端測試的濫用–測試技術2
  • 您應該對什么進行單元測試? –測試技術3
  • 使用模擬的單元測試–測試技術5
  • 為舊版代碼創建存根–測試技術6
  • 有關為舊版代碼創建存根的更多信息–測試技術7
  • 為什么要編寫單元測試–測試技巧8
  • 一些定義–測試技術9
  • 使用FindBugs產生更少的錯誤代碼
  • 在云中開發和測試

翻譯自: https://www.javacodegeeks.com/2011/11/regular-unit-tests-and-stubs-testing.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/374230.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/374230.shtml
英文地址,請注明出處:http://en.pswp.cn/news/374230.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

中微CMS32 Keil環境搭建

打開中微官網https://www.mcu.com.cn/Products/113/pids/.html 把這三個資料都下載好。 環境搭建需要用的就是第三個pack包了 坑爹的是pack包下載下來是.zip格式 下載好后需要修改為.pack格式 運行即可。 打開三個資料中的demo code的工程 target和device都能識別出 編…

Windows下sass無法編譯

最近windows下使用sass老是出現各種莫名其買的問題,下面是我的一些解決辦法 windows下編譯sass不支持中文解決辦法網上給的是 解決辦法: 1.koala可視化編譯工具, 找到安裝目錄里面sass-3.3.7模塊下面的engine.rb文件,例如下面路徑…

數據庫面試中常用的10個問題

1.觸發器的作用?答:觸發器是一中特殊的存儲過程,主要是通過事件來觸發而被執行的。它可以強化約束,來維護數據的完整性和一致性,可以跟蹤數據庫內的操作從而不允許未經許可的更新和變化。可以聯級運算。如&…

測試技巧–不編寫測試

對此沒有太多疑問,測試代碼的方式是一個有爭議的問題。 不同的測試技術因各種原因(包括企業文化,經驗和總體心理觀點)而受到不同開發人員的青睞。 例如,您可能更喜歡編寫經典的單元測試,通過檢查返回值來單…

Ubuntu鏡像下載地址

https://mirrors.aliyun.com/ubuntu-releases/ 用迅雷下載速度挺快的

算法—實現排列 A(n,m)

/* 實現排列A&#xff08;n,m&#xff09;*/ #include "stdio.h" int m,n,a[30]; long s0; int main() {int p(int k);printf("input n(n<10):"); scanf("%d",&n);printf("input m(<1m<n):"); scanf("%d",&…

oracle忘記用戶密碼

在cmd命令行下輸入sqlplus / as sysdba alter user system identified by abc; 就可以將system用戶的密碼改成abc了。 alter user sys identified by abc; sys用戶的密碼也改成abc了。 然后你再登錄sqlplus: 轉載于:https://www.cnblogs.com/zzlp/p/4936109.html

python初體驗-hello world答案_Python初體驗_基礎(一)

一&#xff1a;變量 變量的賦值&#xff1a; name “Meng” 上述代碼聲明了一個變量&#xff0c;變量名為name&#xff0c;變量name的值為&#xff1a;”Meng“ 變量定義&#xff1a; 一個在內存存數據的容器。 變量的意義&#xff1a; 保存程序執行的中間結果或狀態&#xff…

Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum (離線樹狀數組+前綴xor)

題目鏈接&#xff1a;http://codeforces.com/contest/703/problem/D 給你n個數&#xff0c;m次查詢&#xff0c;每次查詢問你l到r之間出現偶數次的數字xor和是多少。 我們可以先預處理前綴和Xor[i]&#xff0c;表示1~i的xor和。因為num^num0&#xff0c;所以Xor[r] ^ Xor[l - 1…

九齊NY8B072A單片機使用筆記(二)TIMER1/2/3定時器

先上代碼 volatile unsigned long g_timer0_delay_conut 0;void main(void) {DISI(); //Disable all unmasked interruptsNy8b072a_Gpio_Init();//Ny8b072a_Timer1_Init();//Ny8b072a_Timer2_Init();Ny8b072a_Timer3_Init();ENI(); // Enable all unmasked interrupts whil…

新的Java緩存標準(javax.cache)

這篇文章探討了新的Java緩存標準&#xff1a;javax.cache。 它如何適應Java生態系統 該標準由JSR107開發&#xff0c;作者是共同規范負責人。 JSR107包含在JSR342開發的Java EE 7中。 Java EE 7將于2012年底完成。但是與此同時&#xff0c;javax.cache將在Java SE 6和更高版本…

Eclipse搭建scala環境(解決“JDT weaving is currently disabled”問題)

隨著Apache Spark&#xff0c;scala也成了必學的語言&#xff0c;下面講一下Eclipse搭建scala開發環境。 網上有很多的教程&#xff0c;但是給的scala的地址下載的插件無法開發scala&#xff0c;會出現“JDT weaving is currently disabled”的問題,這是由于使用了錯誤的Scala地…

python如何輸出結果_如何在python2.7中打印輸出結果?

我正在存儲一些數據&#xff0c;如溫度&#xff0c;濕度和強度&#xff0c;這是我的Arduino輸出和輸入為我的python2.7&#xff0c;我正在繪制圖表的數據。我也想將Arduino輸出存儲到文本文件中&#xff0c;但是我無法這樣做&#xff1a; 這是我的python代碼import serial impo…

python字符串連接的三種方法及其效率、適用場景詳解

python字符串連接的方法&#xff0c;一般有以下三種:方法1&#xff1a;直接通過加號()操作符連接website& 39;python& 39;& 39;tab& 39;& 39; com& 39;方法2 python字符串連接的方法&#xff0c;一般有以下三種: 方法1&#xff1a;直接通過加號()操作符…

算法—遞歸實現 C(m,n)

/* 遞歸實現 C(m,n) */#include "stdio.h" int m,n,s,a[20];int main() {int c(int k);s0; a[0]0;scanf("%d%d",&m,&n);printf("\nC(%d,%d)%d\n",m,n,c(1));}//組合遞歸函數C(k) int c(int k) {int i,j;if(k<n){for(ia[k-1]1;i<m…

九齊51單片機使用注意事項:不要用float

在使用ADC計算電壓值時用了float&#xff0c;NY8B072A堆棧直接炸了&#xff0c;用32機習慣了&#xff0c;一直想不通&#xff0c;查了手冊才知道。 手冊是&#xff1a;《NYC_NY8_UM_v1.5_SC.pdf》 鏈接&#xff1a;https://www.nyquest.com.tw/cn/support/download/Nyquest_SW…

有益的CountDownLatch和棘手的Java死鎖

您是否曾經使用過java.util.concurrent.CountDownLatch &#xff1f; 這是在兩個或多個線程之間實現同步的非常方便的類&#xff0c;在該類中&#xff0c;一個或多個線程可以等待&#xff0c;直到在其他線程中執行的一組操作完成為止&#xff08;請參閱javadoc和此文章 &#x…

算法—回溯法橋本分數式

/* 將1-9九個數不重復地賦給不同的9個元素 &#xff0c;實現形如a/bcd/eff/hi 的形式&#xff1a;例&#xff1a;1/265/784/39 1/325/967/84 &#xff08;注意&#xff1a;1/265/784/39 和5/781/264/39 只能算一種解&#xff09;求滿足條件的解共有多少個&#xff1f; */ #in…

codeforces 703B

題意&#xff1a;有n座城市&#xff0c;其中k座是省會城市&#xff0c;每個城市有對應的點權&#xff0c;城市1-2-3-...-n-1有一條路相連&#xff0c;省會城市與其他所有的城市相連&#xff0c;且每兩個城市間最多有一條路&#xff0c;每條路的邊權為路連接的兩座城市的點權乘積…

go 基準測試 找不到函數_基于Golang做測試

本文在實習期間完成并完善&#xff0c;無任何公司機密&#xff0c;僅做語言交流學習之用。持續更新。1.Golang的單元測試Go語言提供了豐富的單測功能。在Go中&#xff0c;我們通常認為函數是最小的可執行單元。本例中使用兩個簡單的函數&#xff1a;IsOdd和IsPalindrome來進行G…