2012-01-21 28 views
2

我做了一個列表(我通過例子測試驅動開發中所謂的「測試列表」),我將從中選擇一個測試來實現。與TDD相關的知識空洞

所以我啓動Visual Studio中,創建一個新的解決方案,添加一個項目的單元測試,然後...我需要拿出一個類中,我會把測試方法爲我挑選的測試的名單。

這裏是我卡住的地方。我如何知道我需要哪個班級,如何命名以及如何知道它是否正確?這是需要事先考慮的嗎?

回答

0

這是不是一個需要被認爲是提前?

事先。這就是它所謂的「測試驅動開發」的原因...
您必須在開始實施之前設計工作流程

+0

因爲看起來似乎有兩個流派。一種是像在任何項目上那樣準備獲得業務需求,收集用戶故事等,並從那裏開展工作。 另一種方法似乎是完全有機的。除了您希望程序執行的測試之外,您什麼都沒有。 第二種方法阻止我,因爲很難考慮測試的上下文 - 我不知道如何命名我的測試類。但是,也許這也是需要發展的東西。也許我應該給我的測試課一些名字,這會隨着時間的推移而改變? –

+1

@GarthMarenghi。其實我認爲你應該在設計完所有東西之後進行測試,但是在實現一個東西之前。所以只有一種方法。對所有應用程序進行「TDD」太困難了,從小步驟開始。 **祝你好運!** – gdoron

3

您讀過Kent Beck - TDD了嗎?停止嘗試提前全部工作。潛入,做一些事情,讓它工作,不管它是什麼,然後你會對它應該是什麼有更好的想法,並且你可以改變它。校長是這樣的,在你考慮如何去做之前想想你想做什麼。編寫一個測試,測試做你想做的事情,然後實施一個解決方案。第一次,第二次,第三次都會出錯,但這個過程會讓你更接近實際的解決方案,當你完成這個任務時,你應該有寶貴的測試套件和一組鬆散的夫妻班來完成工作完成。

編輯回覆評論

不,不是隨機的名稱。您需要預先執行一定數量的設計。我經常開始提出我認爲我的解決方案需要的關鍵類型。然後我開始一個測試課(說FooTest),我在其中爲我想要Foo做的事情寫一個測試。我使用編寫測試的過程來編寫接口。 ReSharper的是爲這個偉大的,我可以引用尚不存在的類型和方法,並有ReSharper的創建它們:

[TestFixture] 
public class FooTest 
{ 
    [Test] 
    public void Bar() 
    { 
     var foo = (IFoo)null; //At this point I use Resharper to create IFoo interface 

     Assert.IsTrue(foo.Bar()); //At this point I use Resharper to create bool IFoo.Bar(); 
    } 
} 

顯然上述將失敗,空裁判恩,但我有一個測試,我有。一個方法的接口。我可以繼續遵循這個過程來模擬我的解決方案,直到我準備好開發一個具體的實現時達到某個點。在此過程之後,我將重點討論界面和類型之間的交互,而不是這些類型的實現。一旦我建立了Foo,我只需將上面的內容更改爲var foo = new Foo();並使所有測試均爲綠色。這個過程也意味着每個類都有一個接口,這在編寫單元測試時很重要,因爲我可以使用動態模擬庫輕鬆地模擬依賴關係,如MOQ

+0

是的,我讀過它。你是否建議我應該開始給我的班級一個隨機的名字,並從那裏解決?因爲這是我遇到的問題,所以我有一個測試列表,但沒有上下文。 –

0

一個好主意,將開始方面考慮這個,而不是一些模糊測試。例如,你需要制定foo1foo2的功能。

因此,您創建了一個測試類FooTestfoo1Testfoo2Test。最初這些測試會失敗,你只是努力讓他們通過。

+0

因爲似乎有兩種思想流派。一種是像在任何項目上那樣準備獲得業務需求,收集用戶故事等,並從那裏開展工作。另一種方法似乎是完全有機的。除了您希望程序執行的測試之外,您什麼都沒有。第二種方法阻止我,因爲很難考慮測試的上下文 - 我不知道如何命名我的測試類。但是,也許這也是需要發展的東西。也許我應該給我的測試課一些名字,這會隨着時間的推移而改變? –

0

你的系統做什麼?你可以從那裏開始。

假設您正在編寫一個功能,該功能可讀取包含給定帳戶交易的文檔並生成借記和貸記總計摘要。

讓我們創建一個測試:

public class TransactionSummarizationTest { 
    @Test 
    public void summarizesAnEmptyDocument() { 
     TransactionSummarization summarizer = new TransactionSummarization(); 
     Summary s = summarizer.summarizeTransactionsIn(new Scanner()); 
     assertEquals(0.00, s.debits, 0.0); 
     assertEquals(0.00, s.credits, 0.0); 
    } 

由於TransactionSummarizationSummary類還不存在,現在創建它們。他們看起來像這樣:

TransactionSummarization.java

public class TransactionSummarization { 
    public Summary summarizeTransactionsIn(Scanner transactionList) { 
     return null; 
    } 
} 

Summary.java

public class Summary { 
    public double debits; 
    public double credits; 
} 

現在你已經採取了所有可能運行測試編譯錯誤的照顧。由於您執行了summarizeTransactionsIn方法,因此它會因NullPointerException而失敗。從方法返回一個摘要實例,並通過。

public Summary summarizeTransactionsIn(Scanner transactionList) { 
    return new Summary(); 
} 

再次運行您的測試,它通過。

既然您已經完成了第一次測試,接下來會是什麼?我在想,我想用單個事務來嘗試測試。

@Test 
public void summarizesDebit() { 
    TransactionSummarization summarizer = new TransactionSummarization(); 
    Summary s = summarizer.summarizeTransactionsIn(new Scanner("01/01/12,DB,1.00")); 
    assertEquals(1.00, s.debits, 0.0); 
    assertEquals(0.00, s.credits, 0.0); 
} 

運行測試後,我們應該看到它失敗,因爲我們沒有累積值,簡單地返回一個新Summary

public Summary summarizeTransactionsIn(Scanner transactionList) { 
    String currentLine = transactionList.nextLine(); 
    txAmount = currentLine.split(",")[2]; 
    double amount = Double.parseDouble(txAmount); 
    return new Summary(amount); 
} 

Summary固定編譯錯誤之後,實施構造你的測試應該再次通過。下一個測試是什麼?我們可以學習什麼?好吧,我對這個借/貸款事情很好奇,所以我們接下來做。

@Test 
public void summarizesCredit() { 
    TransactionSummarization summarizer = new TransactionSummarization(); 
    Summary s = summarizer.summarizeTransactionsIn(new Scanner("01/01/12,CR,1.00")); 
    assertEquals(0.00, s.debits, 0.0); 
    assertEquals(1.00, s.credits, 0.0); 
} 

運行此測試,我們應該看到它失敗,因爲借方爲1.00,但學分爲0.0。與我們想要的完全相反,但它完全是我們所期望的,因爲我們沒有以任何方式檢查交易類型。現在我們來做。

public Summary summarizeTransactionsIn(Scanner transactionList) { 
    double debits = 0.0; 
    double credits = 0.0; 

    String currentLine = transactionList.nextLine(); 
    String[] data = currentLine.split(","); 
    double amount = Double.parseDouble(data[2]); 

    if("DB".equals(data[1])) 
     debits += amount; 

    if("CR".equals(data[1])) 
     credits += amount; 

    return new Summary(debits, credits); 
} 

現在所有的測試都通過了,我們可以繼續進行下一個測試。怎麼辦?如果我們希望這個項目能夠成功,我認爲只處理文件中的一行對我們無幫助。如何同時處理多個記錄?我們來寫一個測試吧!

@Test 
public void summarizesDebitsAndCredits() { 
    String transactions = "01/01/12,CR,1.75\\n" + 
          "01/02/12,DB,3.00\\n" + 
          "01/02/12,DB,2.50\\n" + 
          "01/02/12,CR,1.25"; 
    TransactionSummarization summarizer = new TransactionSummarization(); 
    Summary s = summarizer.summarizeTransactionsIn(new Scanner(transactions)); 
    assertEquals(5.50, s.debits, 0.0); 
    assertEquals(3.00, s.credits, 0.0); 
} 

現在,運行我們所有的測試,我們看到這一個失敗以可預測的方式。它告訴我們我們的借方是0.00,而且因爲我們只處理了第一筆記錄,所以學分是1.75。

現在我們來修復。一個簡單的while循環,我們應該可以重新開業:

public Summary summarizeTransactionsIn(Scanner transactionList) { 
    double debits = 0.0; 
    double credits = 0.0; 

    while(transactionList.hasLine()) { 
     String currentLine = transactionList.nextLine(); 
     String[] data = currentLine.split(","); 
     double amount = Double.parseDouble(data[2]); 

     if("DB".equals(data[1])) 
      debits += amount; 

     if("CR".equals(data[1])) 
      credits += amount; 
    } 
    return new Summary(debits, credits); 
} 

所有的測試都通過了,我就不打擾休息給你。有些事情需要考慮的是邊緣案例,例如包含混合大小寫的文件,例如「cr」與「CR」,或無效/缺失數據等。

此外,我意識到我輸入了所有你指的C#。不幸的是,我用Java做了它,並且懶得把它轉換成C#,但我希望這有助於它。 :-)

謝謝!

布蘭登