2016-01-19 3 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' в отдельный непубличный метод, а затем вместо оператора' if' для другой проверки использовал оператор 'switch'. – jgauffin

1

Повторение никогда не хорошо (DRY), так подобные тесты должны быть представлены с помощью одного теста. Я не знаком с рамками модульных тестов Microsoft, но в 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

Смежные вопросы