2016-01-19 188 views
0

這裏是TDD的新手。如果我以正確的方式接近,只需要一些指導。我正在尋找使用TDD將羅馬數字字符串轉換爲整數。我有2個關注(還,如果任何人都可以指出的其他問題,請做):這是TDD的正確方法嗎?

  • 這種感覺就像我可寫了太多類似的測試,如 I_returns_1,II_returns_2等等。我應該結合一些這些 測試?或者數到20,我應該真的有20個測試嗎?
  • 我還有足夠的重構嗎?否則,有什麼建議?

    private static readonly Dictionary<string, int> Specials = new Dictionary<string, int>() 
    { 
        {"IV", 4}, 
        {"IX", 9} 
    }; 
    
    public static int? Convert(string input) 
    { 
        if (input == null) return null; 
    
        var processed = input; 
        var counter = 0; 
    
        foreach (var special in Specials) 
        { 
         if (!processed.Contains(special.Key)) continue; 
    
         processed = processed.Replace(special.Key, ""); 
         counter = counter + special.Value; 
        } 
    
        for (int i = 0; i < processed.Length; i++) 
        { 
         if (processed[i] == 'X') 
          counter = counter + 10; 
         if (processed[i] == 'V') 
          counter = counter + 5; 
         if (processed[i] == 'I') 
          counter++; 
        } 
    
        return counter; 
    } 
    

這裏是它上面創建的測試...

所有的
[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void Check_Null_returns_Exception() 
    { 
     var result = Program.Convert(null); 

     Assert.AreEqual(result,null); 
    } 
    [TestMethod] 
    public void I_returns_1() 
    { 
     var result = Program.Convert("I"); 

     Assert.AreEqual(result, 1); 
    } 
    [TestMethod] 
    public void II_returns_2() 
    { 
     var result = Program.Convert("II"); 

     Assert.AreEqual(result, 2); 
    } 

    [TestMethod] 
    public void Multiple_I_returns_number() 
    { 
     var result = Program.Convert("III"); 

     Assert.AreEqual(result, 3); 
    } 

    [TestMethod] 
    public void IV_returns_4() 
    { 
     var result = Program.Convert("IV"); 

     Assert.AreEqual(result, 4); 
    } 

    [TestMethod] 
    public void V_returns_5() 
    { 
     var result = Program.Convert("V"); 

     Assert.AreEqual(result, 5); 
    } 

    [TestMethod] 
    public void VI_returns_6() 
    { 
     var result = Program.Convert("VI"); 

     Assert.AreEqual(result, 6); 
    } 
    [TestMethod] 
    public void VII_returns_7() 
    { 
     var result = Program.Convert("VII"); 

     Assert.AreEqual(7,result); 
    } 
    [TestMethod] 
    public void VIII_returns_8() 
    { 
     var result = Program.Convert("VIII"); 

     Assert.AreEqual(8,result); 
    } 
    [TestMethod] 
    public void IX_returns_9() 
    { 
     var result = Program.Convert("IX"); 

     Assert.AreEqual(9, result); 
    } 

    [TestMethod] 
    public void X_returns_10() 
    { 
     var result = Program.Convert("X"); 

     Assert.AreEqual(10, result); 
    } 

    [TestMethod] 
    public void Test_XI_to_XIII() 
    { 
     Assert.AreEqual(11, Program.Convert("XI")); 
     Assert.AreEqual(12, Program.Convert("XII")); 
     Assert.AreEqual(13, Program.Convert("XIII")); 
    } 
    [TestMethod] 
    public void XIV_returns_14() 
    { 
     var result = Program.Convert("XIV"); 

     Assert.AreEqual(14, result); 
    } 
    [TestMethod] 
    public void XV_returns_15() 
    { 
     var result = Program.Convert("XV"); 

     Assert.AreEqual(15, result); 
    } 

    [TestMethod] 
    public void XVI_returns_16() 
    { 
     var result = Program.Convert("XVI"); 

     Assert.AreEqual(16, result); 
    } 
    [TestMethod] 
    public void XVI_returns_17() 
    { 
     var result = Program.Convert("XVII"); 

     Assert.AreEqual(17, result); 
    } 
    [TestMethod] 
    public void XVI_returns_18() 
    { 
     var result = Program.Convert("XVIII"); 

     Assert.AreEqual(18, result); 
    } 

    [TestMethod] 
    public void XIX_returns_19() 
    { 
     var result = Program.Convert("XIX"); 

     Assert.AreEqual(19, result); 
    } 
    [TestMethod] 
    public void XX_returns_20() 
    { 
     var result = Program.Convert("XX"); 

     Assert.AreEqual(20, result); 
    } 
} 

回答

2

首先,單元測試的名稱應該是有意義的,而不是僅僅描述的代碼。

II_returns_2沒有解釋測試試圖保證什麼。 II_should_be_interpreted_as_the_roman_representation_of_2更好地解釋了業務規則

這一點很重要,因爲當你回來的代碼一年從知道的讀取測試名II_returns_2你就沒有再用線索,爲什麼你寫的測試。 (好吧,在這個微不足道的例子中,你可能會這樣做,但不是在典型的應用程序中)

接下來的事情是方法名稱會相似,但由於代碼路徑不同(應用程序根據羅馬數字)你需要有不同的測試。

幸運的是,一些不同的單元測試庫支持使用屬性來定義一組不同的測試值。

這是xunit的樣本。

[Theory] 
[InlineData("I", 1)] 
[InlineData("II", "2")] 
[InlineData("III", "3")] 
public void test(string roman, int number) 
{ 
    var actual = Program.Convert(roman); 

    Assert.AreEqual(actual, number); 

} 
+0

怎麼樣的算法?你認爲還有改進的餘地嗎? – DrZeuso

+0

@DrZeuso:這是CodeReview站點的問題。但是我會將'Special'塊移動到一個單獨的非公開方法,然後使用'switch'語句而不是'if'語句來進行其他檢查。 – jgauffin

1

重複永遠不好(DRY)所以類似的測試應該用一次測試來表示。我不熟悉微軟的單元測試框架,但在NUnit的,你可以使用TestCase屬性,寫這樣的事:

[TestFixture] 
public class RomanNumeralConverter_Tests 
{ 
    [TestCase("I", 1)] 
    [TestCase("II", 2)] 
    [TestCase("III", 3)] 
    [TestCase("IV", 4)] 
    [TestCase("V", 5)] 
    [TestCase("VI", 6)] 
    // etc... 
    public void Convert_returns_decimal_representation(string roman, int expectedDecimal) 
    { 
     var result = Program.Convert(roman); 
     Assert.AreEqual(expectedDecimal, result); 
    } 
} 
+0

看起來在算法中也有一些重複。你認爲還有改進的餘地嗎? – DrZeuso

相關問題