2011-06-16 160 views
16

我在TD上讀了很多關於TDD和單元測試的問題和答案,但是我沒有發現任何答案:我從哪裏開始?從頭開始TDD項目

我和團隊已經完成了一些項目,其中我們採用了單元測試,用於我們的代碼......但先編碼然後再進行單元測試。在開發過程的某個階段,首先編寫測試代碼然後編寫代碼變得很自然,這使我們獲得了更多的TDD風格。

現在我們想進行下一步,並嘗試從一開始就用TDD啓動一個新項目。這是問題......從哪裏開始?當我沒有代碼時,我會寫的第一個測試是什麼?

比方說,爲了讓上下文思考,我必須開發一個以文檔爲中心的互聯網應用程序,只需要一點工作流程和其他的東西。但是讓我們從頭開始:首先,我想創建一個簡單的頁面,列出存儲在數據庫表格中的所有文檔(元數據)(很簡單,呃?)。 這是我寫的第一個測試?假設我正在使用Hibernate來訪問數據庫...我會測試ipothetical方法getAllDocuments()嗎?但是,我應該使用一個模擬對象來替代Hibernate?那麼我測試了什麼?

我在這裏有點困惑......另外,getAlDocuments()可能永遠不會是一個生產方法......所有文檔集合都會被排序並被某些東西過濾......它有意義嗎? 任何建議將理解

編輯:

讀你的答案(和http://programmers.stackexchange.com相似主題),我帶着TDD的美好憧憬之後,但我仍然有一個dubt。

我總是儘管TDD是關於首先進行單元測試的...從未考慮過端到端測試。 但讓我問:TDD說你必須寫一個測試並看到一個編譯錯誤;然後你創建類和方法,你會得到一個測試失敗;然後你執行該方法並通過測試。在測試失敗之前,您無法編寫代碼;在所有測試通過之前,你不能寫另一個測試。我在這裏嗎?

作爲第一次測試,我該如何進行端到端測試?我應該在所有層中編寫所有代碼,以通過測試。但後來我會有一大堆的類和方法都通過了我的端到端測試(儘管我不應該稱之爲集成測試?)。這意味着我不再需要單元測試,因爲我已經有了一個覆蓋我的代碼的測試。我不能寫一個已經通過的測試,這是違背TDD的實踐。

幫助我理解這個提前進一步的步驟請

+0

我通常從寫入自動加載器組件的測試開始。然後爲我添加的每個班級。 – hakre 2011-06-16 16:37:03

+0

http://programmers.stackexchange.com/questions/84252/tdd-what-happens-before-the-first-unit-test/84255#84255 就在昨天問了同樣的問題。 – 2011-06-16 16:55:55

回答

13

TDD是不是單元測試 - TDD是關於駕駛您的開發和架構的測試 - 與任何類型的,你需要的自動化測試。你看到了這個觀點嗎?

您正在開始一個新項目,並且您可能擁有一組功能。您應該有一些您要實現的功能的驗收標準。這些標準可以定義您的頂級測試。讓我們從一個端到端的測試開始(這可能很難,有時候因爲它涉及到UI尚不存在),或者對這些驗收標準進行集成測試。一旦你的測試失敗了,你將繼續實現與大型測試相關的功能,但是每個這個功能都將通過集成或單元測試再次被驅動。如果所有頂級測試都通過,則該功能已完成。

如果跳過大測試(終端到終端,集成),您將開發一套行之有效的單位,將在整合在一起,或者你的架構不會因爲由單元定義的局部範圍很不錯要麼不工作試驗。集成和端到端測試爲您提供全球範圍。

這在書Growing Object-Oriented Software Guided by Tests中用大的例子(Java)進行了描述。

+0

請查看我更新的問題,並幫助我更深入地瞭解這些概念 – themarcuz 2011-06-30 21:09:47

+0

我檢查了您的更新。我確認我描述的版本是不同的,並且不遵循這種方法(但Kent Beck描述的前TDD也不包括這些規則)。我的描述基於我引用的書,我發現它更有用。無論如何,你仍然可以調整你的流程,並遵循只有單一不完整單元測試的規則,但在單元測試時允許不完整的集成測試。 – 2011-07-04 10:30:18

1

從簡單開始,您將在後面逐步添加功能。從快速設計開始:哪些類,哪些職責,哪些關係。您可以使用CRC cards。不要花太多時間在設計上,因爲稍後您可以通過重構來改進它。選擇最簡單的類來開始實現系統的簡單功能。例如,您可以先創建一個空白頁面。

從一個類開始?它的對象應該做什麼?你如何驗證這是否正確完成?這是第一次測試。

您也可以在沒有數據庫的情況下啓動,並將文檔存儲在平面文件中。稍後您將重構數據庫。然後,您可以從getAllDocuments()函數開始。

2

我通常從上到下開始。在你的情況下,我將開始編寫新頁面的控制器邏輯。通過控制器,我的意思是在UI下面的代碼層,嘲笑下面的所有內容。然後編寫服務層(如果有的話),嘲笑數據層。最後還要測試數據層,並使用基礎類的模擬(可以是您的情況中的ISession)。最後,我會編寫每個數據層方法的單個集成測試並構建頁面(html)。

2

由於您試圖根據測試來推動開發,因此開始的方式是從您的第一個功能開始。例如,讓我們假設您有一個上傳文檔的功能。你的第一個測試可能是:

public class DocumentManagementTest { 
    @Test public void allowsDocumentUploads() { 
    DocumentManagement dm = new DocumentManagement(); 
    Reader mockReader = new MockDocumentReader(); 

    Document result = dm.createDocument("Document name", mockReader); 

    assertEquals("Document name", result.getName()); 
    assertEquals(0, result.getTags().size()); 
    assertTrue(mockReader.fileWasRead); 
    } 
} 

我肯定會模擬出數據庫入手,數據庫的安裝和拆卸是昂貴而脆。記住儘管做出非常小的步驟,但我上面展示的測試可能會在幾次迭代中演變。以吸引更多的設計出後續測試可能是:

@Test public void allowsDocumentRenames() { ... } 
@Test public void allowsAddingTagsToExistingDocuments() { ... } 
@Test public void showsErrorWhenAddingDocumentThatAlreadyExists() { ... } 

一旦你已經建立了一個功能,如createDocument就可以圍繞它的控制器。

public void doPost(HttpServletRequest req, HttpServletResponse resp) { 
    String name = req.getParameter("doc_name"); 
    Document d = docMgmt.createDocument(name, req.getInputStream()); 
    // Hand the newly created document to the view engine. 
} 

我不會太擔心的控制器編寫測試,因爲它從一個複雜的角度來看相當低風險(如果控制器得到太多的代碼,那麼它可能是控制器代碼屬於一個氣味另一個類,可能是您的DocumentManagement類)。

通過一次性構建功能並遵循SOLID原則,您將逐漸發展出一套具有出色測試覆蓋率和相當不錯的面向對象屬性的系統。

乾杯!

布蘭登